001package org.apache.maven.plugin.plugin; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.io.File; 023import java.io.FileNotFoundException; 024import java.io.FileReader; 025import java.util.ArrayList; 026import java.util.Iterator; 027import java.util.List; 028import java.util.Locale; 029import java.util.Map; 030import java.util.ResourceBundle; 031import java.util.Set; 032 033import org.apache.maven.artifact.Artifact; 034import org.apache.maven.artifact.repository.ArtifactRepository; 035import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException; 036import org.apache.maven.artifact.versioning.VersionRange; 037import org.apache.maven.doxia.sink.Sink; 038import org.apache.maven.doxia.siterenderer.Renderer; 039import org.apache.maven.execution.RuntimeInformation; 040import org.apache.maven.model.Plugin; 041import org.apache.maven.plugin.descriptor.InvalidPluginDescriptorException; 042import org.apache.maven.plugin.descriptor.MojoDescriptor; 043import org.apache.maven.plugin.descriptor.PluginDescriptor; 044import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder; 045import org.apache.maven.plugins.annotations.Component; 046import org.apache.maven.plugins.annotations.Execute; 047import org.apache.maven.plugins.annotations.LifecyclePhase; 048import org.apache.maven.plugins.annotations.Mojo; 049import org.apache.maven.plugins.annotations.Parameter; 050import org.apache.maven.plugins.plugin.descriptor.MNG6109PluginDescriptorBuilder; 051import org.apache.maven.project.MavenProject; 052import org.apache.maven.reporting.AbstractMavenReport; 053import org.apache.maven.reporting.AbstractMavenReportRenderer; 054import org.apache.maven.reporting.MavenReportException; 055import org.apache.maven.tools.plugin.DefaultPluginToolsRequest; 056import org.apache.maven.tools.plugin.PluginToolsRequest; 057import org.apache.maven.tools.plugin.extractor.ExtractionException; 058import org.apache.maven.tools.plugin.generator.GeneratorException; 059import org.apache.maven.tools.plugin.generator.GeneratorUtils; 060import org.apache.maven.tools.plugin.generator.PluginXdocGenerator; 061import org.apache.maven.tools.plugin.scanner.MojoScanner; 062import org.apache.maven.tools.plugin.util.PluginUtils; 063import org.codehaus.plexus.component.repository.ComponentDependency; 064import org.codehaus.plexus.configuration.PlexusConfigurationException; 065import org.codehaus.plexus.util.StringUtils; 066import org.codehaus.plexus.util.xml.Xpp3Dom; 067 068/** 069 * Generates the Plugin's documentation report: <code>plugin-info.html</code> plugin overview page, 070 * and one <code><i>goal</i>-mojo.html</code> per goal. 071 * 072 * @author <a href="snicoll@apache.org">Stephane Nicoll</a> 073 * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a> 074 * @since 2.0 075 */ 076@Mojo( name = "report", threadSafe = true ) 077@Execute( phase = LifecyclePhase.PROCESS_CLASSES ) 078public class PluginReport 079 extends AbstractMavenReport 080{ 081 /** 082 * Report output directory for mojos' documentation. 083 */ 084 @Parameter( defaultValue = "${project.build.directory}/generated-site/xdoc" ) 085 private File outputDirectory; 086 087 /** 088 * Doxia Site Renderer. 089 */ 090 @Component 091 private Renderer siteRenderer; 092 093 /** 094 * The Maven Project. 095 */ 096 @Parameter( defaultValue = "${project}", readonly = true ) 097 private MavenProject project; 098 099 /** 100 * Mojo scanner tools. 101 */ 102 @Component 103 protected MojoScanner mojoScanner; 104 105 /** 106 * The file encoding of the source files. 107 * 108 * @since 2.7 109 */ 110 @Parameter( property = "encoding", defaultValue = "${project.build.sourceEncoding}" ) 111 private String encoding; 112 113 /** 114 * Specify some requirements to execute this plugin. 115 * Example: 116 * <pre> 117 * <requirements> 118 * <maven>2.0</maven> 119 * <jdk>1.4</jdk> 120 * <memory>256m</memory> 121 * <diskSpace>1m</diskSpace> 122 * <others> 123 * <property> 124 * <name>SVN</name> 125 * <value>1.4.6</value> 126 * </property> 127 * </others> 128 * </requirements> 129 * </pre> 130 * 131 * If not is specified, Maven requirement is extracted from 132 * <code><project><prerequisites><maven></code> 133 * and JDK requirement is extracted from maven-compiler-plugin configuration. 134 */ 135 @Parameter 136 private Requirements requirements; 137 138 /** 139 * The goal prefix that will appear before the ":". 140 * By default, this plugin applies a heuristic to derive a heuristic from 141 * the plugin's artifactId. 142 * <p/> 143 * It removes any occurrences of the regular expression <strong>-?maven-?</strong>, 144 * and then removes any occurrences of <strong>-?plugin-?</strong>. 145 * <p> 146 * For example, horsefeature-maven-plugin becomes horsefeature. 147 * </p> 148 * <p> 149 * (There is a special case for maven-plugin-plugin: it is mapped to 'plugin') 150 * </p> 151 * 152 * @since 2.4 153 */ 154 @Parameter( property = "goalPrefix" ) 155 protected String goalPrefix; 156 157 /** 158 * Set this to "true" to skip invoking any goals or reports of the plugin. 159 * 160 * @since 2.8 161 */ 162 @Parameter( defaultValue = "false", property = "maven.plugin.skip" ) 163 private boolean skip; 164 165 /** 166 * Set this to "true" to skip generating the report. 167 * 168 * @since 2.8 169 */ 170 @Parameter( defaultValue = "false", property = "maven.plugin.report.skip" ) 171 private boolean skipReport; 172 173 /** 174 * The set of dependencies for the current project 175 * 176 * @since 3.0 177 */ 178 @Parameter( defaultValue = "${project.artifacts}", required = true, readonly = true ) 179 protected Set<Artifact> dependencies; 180 181 /** 182 * List of Remote Repositories used by the resolver 183 * 184 * @since 3.0 185 */ 186 @Parameter( defaultValue = "${project.remoteArtifactRepositories}", required = true, readonly = true ) 187 protected List<ArtifactRepository> remoteRepos; 188 189 /** 190 * Location of the local repository. 191 * 192 * @since 3.0 193 */ 194 @Parameter( defaultValue = "${localRepository}", required = true, readonly = true ) 195 protected ArtifactRepository local; 196 197 /** 198 * @since 3.5.1 199 */ 200 @Component 201 private RuntimeInformation rtInfo; 202 203 /** 204 * Path to {@code plugin.xml} plugin descriptor to generate the report from. 205 * 206 * @since 3.5.1 207 */ 208 @Parameter( defaultValue = "${project.build.outputDirectory}/META-INF/maven/plugin.xml", required = true, 209 readonly = true ) 210 private File pluginXmlFile; 211 212 /** 213 * {@inheritDoc} 214 */ 215 @Override 216 protected Renderer getSiteRenderer() 217 { 218 return siteRenderer; 219 } 220 221 /** 222 * {@inheritDoc} 223 */ 224 @Override 225 protected String getOutputDirectory() 226 { 227 // PLUGIN-191: output directory of plugin.html, not *-mojo.xml 228 return project.getReporting().getOutputDirectory(); 229 } 230 231 /** 232 * {@inheritDoc} 233 */ 234 @Override 235 protected MavenProject getProject() 236 { 237 return project; 238 } 239 240 /** 241 * {@inheritDoc} 242 */ 243 @Override 244 public boolean canGenerateReport() 245 { 246 return pluginXmlFile != null && pluginXmlFile.isFile() && pluginXmlFile.canRead(); 247 } 248 249 /** 250 * {@inheritDoc} 251 */ 252 @Override 253 protected void executeReport( Locale locale ) 254 throws MavenReportException 255 { 256 if ( !canGenerateReport() ) 257 { 258 return; 259 } 260 if ( skip || skipReport ) 261 { 262 getLog().info( "Maven Plugin Plugin Report generation skipped." ); 263 return; 264 } 265 266 PluginDescriptor pluginDescriptor = extractPluginDescriptor(); 267 268 // Generate the mojos' documentation 269 generateMojosDocumentation( pluginDescriptor, locale ); 270 271 // Write the overview 272 PluginOverviewRenderer r = 273 new PluginOverviewRenderer( project, requirements, getSink(), pluginDescriptor, locale ); 274 r.render(); 275 } 276 277 private PluginDescriptor extractPluginDescriptor() 278 throws MavenReportException 279 { 280 PluginDescriptorBuilder builder = getPluginDescriptorBuilder(); 281 282 try 283 { 284 return builder.build( new FileReader( pluginXmlFile ) ); 285 } 286 catch ( FileNotFoundException e ) 287 { 288 getLog().debug( "Failed to read " + pluginXmlFile + ", fall back to mojoScanner" ); 289 } 290 catch ( PlexusConfigurationException e ) 291 { 292 getLog().debug( "Failed to read " + pluginXmlFile + ", fall back to mojoScanner" ); 293 } 294 295 // Copy from AbstractGeneratorMojo#execute() 296 String defaultGoalPrefix = PluginDescriptor.getGoalPrefixFromArtifactId( project.getArtifactId() ); 297 if ( goalPrefix == null ) 298 { 299 goalPrefix = defaultGoalPrefix; 300 } 301 else 302 { 303 getLog().warn( "\n\nGoal prefix is specified as: '" + goalPrefix + "'. Maven currently expects it to be '" 304 + defaultGoalPrefix + "'.\n" ); 305 } 306 307 // TODO: could use this more, eg in the writing of the plugin descriptor! 308 PluginDescriptor pluginDescriptor = new PluginDescriptor(); 309 310 pluginDescriptor.setGroupId( project.getGroupId() ); 311 312 pluginDescriptor.setArtifactId( project.getArtifactId() ); 313 314 pluginDescriptor.setVersion( project.getVersion() ); 315 316 pluginDescriptor.setGoalPrefix( goalPrefix ); 317 318 try 319 { 320 @SuppressWarnings( "unchecked" ) 321 List<ComponentDependency> deps = GeneratorUtils.toComponentDependencies( project.getRuntimeDependencies() ); 322 pluginDescriptor.setDependencies( deps ); 323 324 PluginToolsRequest request = new DefaultPluginToolsRequest( project, pluginDescriptor ); 325 request.setEncoding( encoding ); 326 request.setSkipErrorNoDescriptorsFound( true ); 327 request.setDependencies( dependencies ); 328 request.setLocal( this.local ); 329 request.setRemoteRepos( this.remoteRepos ); 330 331 try 332 { 333 mojoScanner.populatePluginDescriptor( request ); 334 } 335 catch ( InvalidPluginDescriptorException e ) 336 { 337 // this is OK, it happens to lifecycle plugins. Allow generation to proceed. 338 getLog().debug( "Plugin without mojos.", e ); 339 } 340 } 341 catch ( ExtractionException e ) 342 { 343 throw new MavenReportException( "Error extracting plugin descriptor: \'" + e.getLocalizedMessage() + "\'", 344 e ); 345 } 346 return pluginDescriptor; 347 } 348 349 /** 350 * Return the pluginDescriptorBuilder to use based on the Maven version: either use the original from the 351 * maven-plugin-api or a patched version for Maven versions before the MNG-6109 fix 352 * (because of Maven MNG-6109 bug that won't give accurate 'since' info when reading plugin.xml). 353 * 354 * @return the proper pluginDescriptorBuilder 355 * @see https://issues.apache.org/jira/browse/MNG-6109 356 * @see https://issues.apache.org/jira/browse/MPLUGIN-319 357 */ 358 private PluginDescriptorBuilder getPluginDescriptorBuilder() 359 { 360 PluginDescriptorBuilder pluginDescriptorBuilder; 361 try 362 { 363 VersionRange versionRange = VersionRange.createFromVersionSpec( "(3.3.9,)" ); 364 if ( versionRange.containsVersion( rtInfo.getApplicationVersion() ) ) 365 { 366 pluginDescriptorBuilder = new PluginDescriptorBuilder(); 367 } 368 else 369 { 370 pluginDescriptorBuilder = new MNG6109PluginDescriptorBuilder(); 371 } 372 } 373 catch ( InvalidVersionSpecificationException e ) 374 { 375 return new MNG6109PluginDescriptorBuilder(); 376 } 377 378 return pluginDescriptorBuilder; 379 } 380 381 /** 382 * {@inheritDoc} 383 */ 384 @Override 385 public String getDescription( Locale locale ) 386 { 387 return getBundle( locale ).getString( "report.plugin.description" ); 388 } 389 390 /** 391 * {@inheritDoc} 392 */ 393 @Override 394 public String getName( Locale locale ) 395 { 396 return getBundle( locale ).getString( "report.plugin.name" ); 397 } 398 399 /** 400 * {@inheritDoc} 401 */ 402 @Override 403 public String getOutputName() 404 { 405 return "plugin-info"; 406 } 407 408 /** 409 * Generate the mojos documentation, as xdoc files. 410 * 411 * @param pluginDescriptor not null 412 * @param locale not null 413 * @throws MavenReportException if any 414 */ 415 private void generateMojosDocumentation( PluginDescriptor pluginDescriptor, Locale locale ) 416 throws MavenReportException 417 { 418 try 419 { 420 File outputDir = outputDirectory; 421 outputDir.mkdirs(); 422 423 PluginXdocGenerator generator = new PluginXdocGenerator( project, locale ); 424 PluginToolsRequest pluginToolsRequest = new DefaultPluginToolsRequest( project, pluginDescriptor ); 425 generator.execute( outputDir, pluginToolsRequest ); 426 } 427 catch ( GeneratorException e ) 428 { 429 throw new MavenReportException( "Error writing plugin documentation", e ); 430 } 431 432 } 433 434 /** 435 * @param locale not null 436 * @return the bundle for this report 437 */ 438 protected static ResourceBundle getBundle( Locale locale ) 439 { 440 return ResourceBundle.getBundle( "plugin-report", locale, PluginReport.class.getClassLoader() ); 441 } 442 443 /** 444 * Generates an overview page with the list of goals 445 * and a link to the goal's page. 446 */ 447 static class PluginOverviewRenderer 448 extends AbstractMavenReportRenderer 449 { 450 private final MavenProject project; 451 452 private final Requirements requirements; 453 454 private final PluginDescriptor pluginDescriptor; 455 456 private final Locale locale; 457 458 /** 459 * @param project not null 460 * @param requirements not null 461 * @param sink not null 462 * @param pluginDescriptor not null 463 * @param locale not null 464 */ 465 PluginOverviewRenderer( MavenProject project, Requirements requirements, Sink sink, 466 PluginDescriptor pluginDescriptor, Locale locale ) 467 { 468 super( sink ); 469 470 this.project = project; 471 472 this.requirements = ( requirements == null ? new Requirements() : requirements ); 473 474 this.pluginDescriptor = pluginDescriptor; 475 476 this.locale = locale; 477 } 478 479 /** 480 * {@inheritDoc} 481 */ 482 @Override 483 public String getTitle() 484 { 485 return getBundle( locale ).getString( "report.plugin.title" ); 486 } 487 488 /** 489 * {@inheritDoc} 490 */ 491 @Override 492 @SuppressWarnings( { "unchecked", "rawtypes" } ) 493 public void renderBody() 494 { 495 startSection( getTitle() ); 496 497 if ( !( pluginDescriptor.getMojos() != null && pluginDescriptor.getMojos().size() > 0 ) ) 498 { 499 paragraph( getBundle( locale ).getString( "report.plugin.goals.nogoal" ) ); 500 endSection(); 501 return; 502 } 503 504 paragraph( getBundle( locale ).getString( "report.plugin.goals.intro" ) ); 505 506 boolean hasMavenReport = false; 507 for ( Iterator<MojoDescriptor> i = pluginDescriptor.getMojos().iterator(); i.hasNext(); ) 508 { 509 MojoDescriptor mojo = i.next(); 510 511 if ( GeneratorUtils.isMavenReport( mojo.getImplementation(), project ) ) 512 { 513 hasMavenReport = true; 514 } 515 } 516 517 startTable(); 518 519 String goalColumnName = getBundle( locale ).getString( "report.plugin.goals.column.goal" ); 520 String isMavenReport = getBundle( locale ).getString( "report.plugin.goals.column.isMavenReport" ); 521 String descriptionColumnName = getBundle( locale ).getString( "report.plugin.goals.column.description" ); 522 if ( hasMavenReport ) 523 { 524 tableHeader( new String[]{ goalColumnName, isMavenReport, descriptionColumnName } ); 525 } 526 else 527 { 528 tableHeader( new String[]{ goalColumnName, descriptionColumnName } ); 529 } 530 531 List<MojoDescriptor> mojos = new ArrayList<MojoDescriptor>(); 532 mojos.addAll( pluginDescriptor.getMojos() ); 533 PluginUtils.sortMojos( mojos ); 534 for ( MojoDescriptor mojo : mojos ) 535 { 536 String goalName = mojo.getFullGoalName(); 537 538 /* 539 * Added ./ to define a relative path 540 * @see AbstractMavenReportRenderer#getValidHref(java.lang.String) 541 */ 542 String goalDocumentationLink = "./" + mojo.getGoal() + "-mojo.html"; 543 544 String description; 545 if ( StringUtils.isNotEmpty( mojo.getDeprecated() ) ) 546 { 547 description = 548 "<strong>" + getBundle( locale ).getString( "report.plugin.goal.deprecated" ) + "</strong> " 549 + GeneratorUtils.makeHtmlValid( mojo.getDeprecated() ); 550 } 551 else if ( StringUtils.isNotEmpty( mojo.getDescription() ) ) 552 { 553 description = GeneratorUtils.makeHtmlValid( mojo.getDescription() ); 554 } 555 else 556 { 557 description = getBundle( locale ).getString( "report.plugin.goal.nodescription" ); 558 } 559 560 sink.tableRow(); 561 tableCell( createLinkPatternedText( goalName, goalDocumentationLink ) ); 562 if ( hasMavenReport ) 563 { 564 if ( GeneratorUtils.isMavenReport( mojo.getImplementation(), project ) ) 565 { 566 sink.tableCell(); 567 sink.text( getBundle( locale ).getString( "report.plugin.isReport" ) ); 568 sink.tableCell_(); 569 } 570 else 571 { 572 sink.tableCell(); 573 sink.text( getBundle( locale ).getString( "report.plugin.isNotReport" ) ); 574 sink.tableCell_(); 575 } 576 } 577 tableCell( description, true ); 578 sink.tableRow_(); 579 } 580 581 endTable(); 582 583 startSection( getBundle( locale ).getString( "report.plugin.systemrequirements" ) ); 584 585 paragraph( getBundle( locale ).getString( "report.plugin.systemrequirements.intro" ) ); 586 587 startTable(); 588 589 String maven = discoverMavenRequirement( project, requirements ); 590 sink.tableRow(); 591 tableCell( getBundle( locale ).getString( "report.plugin.systemrequirements.maven" ) ); 592 tableCell( ( maven != null 593 ? maven 594 : getBundle( locale ).getString( "report.plugin.systemrequirements.nominimum" ) ) ); 595 sink.tableRow_(); 596 597 String jdk = discoverJdkRequirement( project, requirements ); 598 sink.tableRow(); 599 tableCell( getBundle( locale ).getString( "report.plugin.systemrequirements.jdk" ) ); 600 tableCell( 601 ( jdk != null ? jdk : getBundle( locale ).getString( "report.plugin.systemrequirements.nominimum" ) ) ); 602 sink.tableRow_(); 603 604 sink.tableRow(); 605 tableCell( getBundle( locale ).getString( "report.plugin.systemrequirements.memory" ) ); 606 tableCell( ( StringUtils.isNotEmpty( requirements.getMemory() ) 607 ? requirements.getMemory() 608 : getBundle( locale ).getString( "report.plugin.systemrequirements.nominimum" ) ) ); 609 sink.tableRow_(); 610 611 sink.tableRow(); 612 tableCell( getBundle( locale ).getString( "report.plugin.systemrequirements.diskspace" ) ); 613 tableCell( ( StringUtils.isNotEmpty( requirements.getDiskSpace() ) 614 ? requirements.getDiskSpace() 615 : getBundle( locale ).getString( "report.plugin.systemrequirements.nominimum" ) ) ); 616 sink.tableRow_(); 617 618 if ( requirements.getOthers() != null && requirements.getOthers().size() > 0 ) 619 { 620 for ( Iterator it = requirements.getOthers().keySet().iterator(); it.hasNext(); ) 621 { 622 String key = it.next().toString(); 623 624 sink.tableRow(); 625 tableCell( key ); 626 tableCell( ( StringUtils.isNotEmpty( requirements.getOthers().getProperty( key ) ) 627 ? requirements.getOthers().getProperty( key ) 628 : getBundle( locale ).getString( "report.plugin.systemrequirements.nominimum" ) ) ); 629 sink.tableRow_(); 630 } 631 } 632 endTable(); 633 634 endSection(); 635 636 renderUsageSection( hasMavenReport ); 637 638 endSection(); 639 } 640 641 /** 642 * Render the section about the usage of the plugin. 643 * 644 * @param hasMavenReport If the plugin has a report or not 645 */ 646 private void renderUsageSection( boolean hasMavenReport ) 647 { 648 startSection( getBundle( locale ).getString( "report.plugin.usage" ) ); 649 650 // Configuration 651 sink.paragraph(); 652 text( getBundle( locale ).getString( "report.plugin.usage.intro" ) ); 653 sink.paragraph_(); 654 655 StringBuilder sb = new StringBuilder(); 656 sb.append( "<project>" ).append( '\n' ); 657 sb.append( " ..." ).append( '\n' ); 658 sb.append( " <build>" ).append( '\n' ); 659 sb.append( 660 " <!-- " + getBundle( locale ).getString( "report.plugin.usage.pluginManagement" ) + " -->" ).append( 661 '\n' ); 662 sb.append( " <pluginManagement>" ).append( '\n' ); 663 sb.append( " <plugins>" ).append( '\n' ); 664 sb.append( " <plugin>" ).append( '\n' ); 665 sb.append( " <groupId>" ).append( pluginDescriptor.getGroupId() ).append( "</groupId>" ).append( 666 '\n' ); 667 sb.append( " <artifactId>" ).append( pluginDescriptor.getArtifactId() ).append( 668 "</artifactId>" ).append( '\n' ); 669 sb.append( " <version>" ).append( pluginDescriptor.getVersion() ).append( "</version>" ).append( 670 '\n' ); 671 sb.append( " </plugin>" ).append( '\n' ); 672 sb.append( " ..." ).append( '\n' ); 673 sb.append( " </plugins>" ).append( '\n' ); 674 sb.append( " </pluginManagement>" ).append( '\n' ); 675 sb.append( " <!-- " + getBundle( locale ).getString( "report.plugin.usage.plugins" ) + " -->" ).append( 676 '\n' ); 677 sb.append( " <plugins>" ).append( '\n' ); 678 sb.append( " <plugin>" ).append( '\n' ); 679 sb.append( " <groupId>" ).append( pluginDescriptor.getGroupId() ).append( "</groupId>" ).append( 680 '\n' ); 681 sb.append( " <artifactId>" ).append( pluginDescriptor.getArtifactId() ).append( 682 "</artifactId>" ).append( '\n' ); 683 sb.append( " <version>" ).append( pluginDescriptor.getVersion() ).append( "</version>" ).append( 684 '\n' ); 685 sb.append( " </plugin>" ).append( '\n' ); 686 sb.append( " ..." ).append( '\n' ); 687 sb.append( " </plugins>" ).append( '\n' ); 688 sb.append( " </build>" ).append( '\n' ); 689 690 if ( hasMavenReport ) 691 { 692 sb.append( " ..." ).append( '\n' ); 693 sb.append( 694 " <!-- " + getBundle( locale ).getString( "report.plugin.usage.reporting" ) + " -->" ).append( 695 '\n' ); 696 sb.append( " <reporting>" ).append( '\n' ); 697 sb.append( " <plugins>" ).append( '\n' ); 698 sb.append( " <plugin>" ).append( '\n' ); 699 sb.append( " <groupId>" ).append( pluginDescriptor.getGroupId() ).append( "</groupId>" ).append( 700 '\n' ); 701 sb.append( " <artifactId>" ).append( pluginDescriptor.getArtifactId() ).append( 702 "</artifactId>" ).append( '\n' ); 703 sb.append( " <version>" ).append( pluginDescriptor.getVersion() ).append( "</version>" ).append( 704 '\n' ); 705 sb.append( " </plugin>" ).append( '\n' ); 706 sb.append( " ..." ).append( '\n' ); 707 sb.append( " </plugins>" ).append( '\n' ); 708 sb.append( " </reporting>" ).append( '\n' ); 709 } 710 711 sb.append( " ..." ).append( '\n' ); 712 sb.append( "</project>" ).append( '\n' ); 713 714 verbatimText( sb.toString() ); 715 716 sink.paragraph(); 717 linkPatternedText( getBundle( locale ).getString( "report.plugin.configuration.end" ) ); 718 sink.paragraph_(); 719 720 endSection(); 721 } 722 723 /** 724 * Try to lookup on the Maven prerequisites property. 725 * If not specified, uses the value defined by the user. 726 * 727 * @param project not null 728 * @param requirements not null 729 * @return the Maven version 730 */ 731 private static String discoverMavenRequirement( MavenProject project, Requirements requirements ) 732 { 733 String maven = requirements.getMaven(); 734 if ( maven == null ) 735 { 736 maven = ( project.getPrerequisites() != null ? project.getPrerequisites().getMaven() : null ); 737 } 738 if ( maven == null ) 739 { 740 maven = "2.0"; 741 } 742 743 return maven; 744 } 745 746 /** 747 * <ol> 748 * <li>use configured jdk requirement</li> 749 * <li>use <code>target</code> configuration of <code>org.apache.maven.plugins:maven-compiler-plugin</code></li> 750 * <li>use <code>target</code> configuration of <code>org.apache.maven.plugins:maven-compiler-plugin</code> in 751 * <code>pluginManagement</code></li> 752 * <li>use <code>maven.compiler.target</code> property</li> 753 * </ol> 754 * 755 * @param project not null 756 * @param requirements not null 757 * @return the JDK version 758 */ 759 private static String discoverJdkRequirement( MavenProject project, Requirements requirements ) 760 { 761 String jdk = requirements.getJdk(); 762 763 if ( jdk != null ) 764 { 765 return jdk; 766 } 767 768 @SuppressWarnings( "unchecked" ) 769 Plugin compiler = getCompilerPlugin( project.getBuild().getPluginsAsMap() ); 770 if ( compiler == null ) 771 { 772 compiler = getCompilerPlugin( project.getPluginManagement().getPluginsAsMap() ); 773 } 774 775 jdk = getPluginParameter( compiler, "target" ); 776 if ( jdk != null ) 777 { 778 return jdk; 779 } 780 781 // default value 782 jdk = project.getProperties().getProperty( "maven.compiler.target" ); 783 if ( jdk != null ) 784 { 785 return jdk; 786 } 787 788 // return "1.5" by default? 789 790 String version = ( compiler == null ) ? null : compiler.getVersion(); 791 792 if ( version != null ) 793 { 794 return "Default target for maven-compiler-plugin version " + version; 795 } 796 797 return "Unknown"; 798 } 799 800 private static Plugin getCompilerPlugin( Map<String, Object> pluginsAsMap ) 801 { 802 return (Plugin) pluginsAsMap.get( "org.apache.maven.plugins:maven-compiler-plugin" ); 803 } 804 805 private static String getPluginParameter( Plugin plugin, String parameter ) 806 { 807 if ( plugin != null ) 808 { 809 Xpp3Dom pluginConf = (Xpp3Dom) plugin.getConfiguration(); 810 811 if ( pluginConf != null ) 812 { 813 Xpp3Dom target = pluginConf.getChild( parameter ); 814 815 if ( target != null ) 816 { 817 return target.getValue(); 818 } 819 } 820 } 821 822 return null; 823 } 824 } 825}