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