View Javadoc
1   package org.apache.maven.plugin.plugin.report_old;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.io.Reader;
25  import java.nio.file.Files;
26  import java.util.ArrayList;
27  import java.util.Iterator;
28  import java.util.List;
29  import java.util.Locale;
30  import java.util.Map;
31  import java.util.ResourceBundle;
32  
33  import org.apache.maven.doxia.sink.Sink;
34  import org.apache.maven.model.Plugin;
35  import org.apache.maven.plugin.descriptor.MojoDescriptor;
36  import org.apache.maven.plugin.descriptor.PluginDescriptor;
37  import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder;
38  import org.apache.maven.plugin.plugin.DescriptorGeneratorMojo;
39  import org.apache.maven.plugins.annotations.Component;
40  import org.apache.maven.plugins.annotations.Execute;
41  import org.apache.maven.plugins.annotations.LifecyclePhase;
42  import org.apache.maven.plugins.annotations.Mojo;
43  import org.apache.maven.plugins.annotations.Parameter;
44  import org.apache.maven.plugins.plugin.descriptor_old.EnhancedPluginDescriptorBuilder;
45  import org.apache.maven.project.MavenProject;
46  import org.apache.maven.reporting.AbstractMavenReport;
47  import org.apache.maven.reporting.AbstractMavenReportRenderer;
48  import org.apache.maven.reporting.MavenReportException;
49  import org.apache.maven.rtinfo.RuntimeInformation;
50  import org.apache.maven.tools.plugin.DefaultPluginToolsRequest;
51  import org.apache.maven.tools.plugin.PluginToolsRequest;
52  import org.apache.maven.tools.plugin.generator.GeneratorException;
53  import org.apache.maven.tools.plugin.generator.GeneratorUtils;
54  import org.apache.maven.tools.plugin.generator.PluginXdocGenerator;
55  import org.apache.maven.tools.plugin.util.PluginUtils;
56  import org.codehaus.plexus.configuration.PlexusConfigurationException;
57  import org.codehaus.plexus.util.StringUtils;
58  import org.codehaus.plexus.util.xml.XmlStreamReader;
59  import org.codehaus.plexus.util.xml.Xpp3Dom;
60  
61  /**
62   * Generates the Plugin's documentation report: <code>plugin-info.html</code> plugin overview page,
63   * and one <code><i>goal</i>-mojo.html</code> per goal.
64   * Relies on one output file from {@link DescriptorGeneratorMojo}.
65   *
66   * @author <a href="snicoll@apache.org">Stephane Nicoll</a>
67   * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
68   * @since 2.0
69   * @deprecated use the maven-plugin-report-plugin instead
70   */
71  @Deprecated
72  @Mojo( name = "report", threadSafe = true )
73  @Execute( phase = LifecyclePhase.PROCESS_CLASSES )
74  public class PluginReport
75      extends AbstractMavenReport
76  {
77      /**
78       * Report output directory for mojos' documentation.
79       */
80      @Parameter( defaultValue = "${project.build.directory}/generated-site/xdoc" )
81      private File outputDirectory;
82  
83      /**
84       * The file encoding of the source files.
85       *
86       * @deprecated not used in report, will be removed in the next major version
87       *
88       * @since 2.7
89       */
90      @Deprecated
91      @Parameter( property = "encoding", defaultValue = "${project.build.sourceEncoding}" )
92      private String encoding;
93  
94      /**
95       * Specify some requirements to execute this plugin.
96       * Example:
97       * <pre>
98       * &lt;requirements&gt;
99       *   &lt;maven&gt;2.0&lt;/maven&gt;
100      *   &lt;jdk&gt;1.4&lt;/jdk&gt;
101      *   &lt;memory&gt;256m&lt;/memory&gt;
102      *   &lt;diskSpace&gt;1m&lt;/diskSpace&gt;
103      *   &lt;others&gt;
104      *     &lt;property&gt;
105      *       &lt;name&gt;SVN&lt;/name&gt;
106      *       &lt;value&gt;1.4.6&lt;/value&gt;
107      *     &lt;/property&gt;
108      *   &lt;/others&gt;
109      * &lt;/requirements&gt;
110      * </pre>
111      * <p>
112      * If not is specified, Maven requirement is extracted from
113      * <code>&lt;project&gt;&lt;prerequisites&gt;&lt;maven&gt;</code>
114      * and JDK requirement is extracted from maven-compiler-plugin configuration.
115      *
116      * @deprecated will be removed in the next major version, please don't use
117      */
118     @Deprecated
119     @Parameter
120     private Requirements requirements;
121 
122     /**
123      * <p>
124      * The goal prefix that will appear before the ":".
125      * By default, this plugin applies a heuristic to derive a heuristic from
126      * the plugin's artifactId.
127      * </p>
128      * <p>
129      * It removes any occurrences of the regular expression <strong>-?maven-?</strong>,
130      * and then removes any occurrences of <strong>-?plugin-?</strong>.
131      * </p>
132      * <p>
133      * For example, horsefeature-maven-plugin becomes horsefeature.
134      * </p>
135      * <p>
136      * (There is a special case for maven-plugin-plugin: it is mapped to 'plugin')
137      * </p>
138      *
139      * @deprecated not used in report, will be removed in the next major version
140      *
141      * @since 2.4
142      */
143     @Deprecated
144     @Parameter( property = "goalPrefix" )
145     protected String goalPrefix;
146 
147     /**
148      * Set this to "true" to skip invoking any goals or reports of the plugin.
149      *
150      * @deprecated use {@link #skip} parameter instead
151      *
152      * @since 2.8
153      */
154     @Deprecated
155     @Parameter( defaultValue = "false", property = "maven.plugin.skip" )
156     private boolean skipReport;
157 
158     /**
159      * Set this to "true" to skip generating the report.
160      *
161      * @since 2.8
162      */
163     @Parameter( defaultValue = "false", property = "maven.plugin.report.skip" )
164     private boolean skip;
165 
166     /**
167      * Set this to "true" to generate the usage section for "plugin-info.html" with
168      * {@code <extensions>true</extensions>}.
169      *
170      * @since 3.7.0
171      */
172     @Parameter( defaultValue = "false", property = "maven.plugin.report.hasExtensionsToLoad" )
173     private boolean hasExtensionsToLoad;
174 
175     /**
176      * The Plugin requirements history list.
177      * <p>
178      * Can be specified as list of <code>requirementsHistory</code>:
179      *
180      * <pre>
181      * &lt;requirementsHistories&gt;
182      *   &lt;requirementsHistory&gt;
183      *     &lt;version&gt;plugin version&lt;/version&gt;
184      *     &lt;maven&gt;maven version&lt;/maven&gt;
185      *     &lt;jdk&gt;jdk version&lt;/jdk&gt;
186      *   &lt;/requirementsHistory&gt;
187      * &lt;/requirementsHistories&gt;
188      * </pre>
189      *
190      * @since 3.7.0
191      */
192     @Parameter
193     private List<RequirementsHistory> requirementsHistories = new ArrayList<>();
194 
195     /**
196      * @since 3.5.1
197      */
198     @Component
199     private RuntimeInformation rtInfo;
200 
201     /**
202      * Path to {@code plugin.xml} plugin descriptor to generate the report from.
203      *
204      * @since 3.5.1
205      * @deprecated No longer evaluated, use {@link #enhancedPluginXmlFile}.
206      */
207     @Parameter( defaultValue = "${project.build.outputDirectory}/META-INF/maven/plugin.xml", required = true,
208                 readonly = true )
209     @Deprecated
210     private File pluginXmlFile;
211 
212     /**
213      * Path to enhanced plugin descriptor to generate the report from (must contain some XHTML values)
214      *
215      * @since 3.7.0
216      */
217     @Parameter( defaultValue = "${project.build.directory}/plugin-enhanced.xml", required = true,
218                 readonly = true )
219     private File enhancedPluginXmlFile;
220 
221     /**
222      * In case the internal javadoc site has not been generated when running this report goal
223      * (e.g. when using an aggregator javadoc report) link validation needs to be disabled by setting
224      * this value to {@code true}.
225      * This might have the drawback that some links being generated in the report might be broken
226      * in case not all parameter types and javadoc link references are resolvable through the sites being given to
227      * {@link DescriptorGeneratorMojo}.
228      * 
229      * @since 3.7.0
230      */
231     @Parameter( property = "maven.plugin.report.disableInternalJavadocLinkValidation" )
232     private boolean disableInternalJavadocLinkValidation;
233 
234     /**
235      * {@inheritDoc}
236      */
237     @Override
238     protected String getOutputDirectory()
239     {
240         // PLUGIN-191: output directory of plugin.html, not *-mojo.xml
241         return project.getReporting().getOutputDirectory();
242     }
243 
244     /**
245      * {@inheritDoc}
246      */
247     @Override
248     public boolean canGenerateReport()
249     {
250         return enhancedPluginXmlFile != null && enhancedPluginXmlFile.isFile() && enhancedPluginXmlFile.canRead();
251     }
252 
253     /**
254      * {@inheritDoc}
255      */
256     @Override
257     protected void executeReport( Locale locale )
258         throws MavenReportException
259     {
260         getLog().warn( "The 'report' goal of the maven-plugin-plugin is deprecated, please use "
261                 + "the 'report' goal from the maven-plugin-report-plugin instead. This goal will be removed "
262                 + "in version 4.0.0." );
263 
264         if ( skip || skipReport )
265         {
266             getLog().info( "Maven Plugin Plugin Report generation skipped." );
267             return;
268         }
269 
270         PluginDescriptor pluginDescriptor = extractPluginDescriptor();
271 
272         // Generate the mojos' documentation
273         generateMojosDocumentation( pluginDescriptor, locale );
274 
275         // Write the overview
276         PluginOverviewRenderer r =
277             new PluginOverviewRenderer( getProject(), requirements, requirementsHistories, getSink(),
278                                         pluginDescriptor, locale, hasExtensionsToLoad );
279         r.render();
280     }
281 
282     private PluginDescriptor extractPluginDescriptor()
283         throws MavenReportException
284     {
285         PluginDescriptorBuilder builder = new EnhancedPluginDescriptorBuilder( rtInfo );
286 
287         try ( Reader input = new XmlStreamReader( Files.newInputStream( enhancedPluginXmlFile.toPath() ) ) )
288         {
289             return builder.build( input );
290         }
291         catch ( IOException | PlexusConfigurationException e )
292         {
293             throw new MavenReportException( "Error extracting plugin descriptor from " + enhancedPluginXmlFile, e );
294         }
295 
296     }
297 
298     /**
299      * {@inheritDoc}
300      */
301     @Override
302     public String getDescription( Locale locale )
303     {
304         return getBundle( locale ).getString( "report.plugin.description" );
305     }
306 
307     /**
308      * {@inheritDoc}
309      */
310     @Override
311     public String getName( Locale locale )
312     {
313         return getBundle( locale ).getString( "report.plugin.name" );
314     }
315 
316     /**
317      * {@inheritDoc}
318      */
319     @Override
320     public String getOutputName()
321     {
322         return "plugin-info";
323     }
324 
325     /**
326      * Generate the mojos documentation, as xdoc files.
327      *
328      * @param pluginDescriptor not null
329      * @param locale           not null
330      * @throws MavenReportException if any
331      */
332     private void generateMojosDocumentation( PluginDescriptor pluginDescriptor, Locale locale )
333         throws MavenReportException
334     {
335         try
336         {
337             File outputDir = outputDirectory;
338             outputDir.mkdirs();
339 
340             PluginXdocGenerator generator = new PluginXdocGenerator( getProject(), locale, getReportOutputDirectory(),
341                                                                      disableInternalJavadocLinkValidation );
342             PluginToolsRequest pluginToolsRequest = new DefaultPluginToolsRequest( getProject(), pluginDescriptor );
343             generator.execute( outputDir, pluginToolsRequest );
344         }
345         catch ( GeneratorException e )
346         {
347             throw new MavenReportException( "Error writing plugin documentation", e );
348         }
349 
350     }
351 
352     /**
353      * @param locale not null
354      * @return the bundle for this report
355      */
356     protected static ResourceBundle getBundle( Locale locale )
357     {
358         return ResourceBundle.getBundle( "plugin-report", locale, PluginReport.class.getClassLoader() );
359     }
360 
361     /**
362      * Generates an overview page with the list of goals
363      * and a link to the goal's page.
364      */
365     static class PluginOverviewRenderer
366         extends AbstractMavenReportRenderer
367     {
368         private final MavenProject project;
369 
370         private final Requirements requirements;
371 
372         private final List<RequirementsHistory> requirementsHistories;
373 
374         private final PluginDescriptor pluginDescriptor;
375 
376         private final Locale locale;
377 
378         private final boolean hasExtensionsToLoad;
379 
380         /**
381          * @param project               not null
382          * @param requirements          not null
383          * @param requirementsHistories not null
384          * @param sink                  not null
385          * @param pluginDescriptor      not null
386          * @param locale                not null
387          */
388         PluginOverviewRenderer( MavenProject project, Requirements requirements,
389                                 List<RequirementsHistory> requirementsHistories, Sink sink,
390                                 PluginDescriptor pluginDescriptor, Locale locale, boolean hasExtensionsToLoad )
391         {
392             super( sink );
393 
394             this.project = project;
395 
396             this.requirements = ( requirements == null ? new Requirements() : requirements );
397 
398             this.requirementsHistories = requirementsHistories;
399 
400             this.pluginDescriptor = pluginDescriptor;
401 
402             this.locale = locale;
403 
404             this.hasExtensionsToLoad = hasExtensionsToLoad;
405         }
406 
407         /**
408          * {@inheritDoc}
409          */
410         @Override
411         public String getTitle()
412         {
413             return getBundle( locale ).getString( "report.plugin.title" );
414         }
415 
416         /**
417          * {@inheritDoc}
418          */
419         @Override
420         public void renderBody()
421         {
422             startSection( getTitle() );
423 
424             if ( !( pluginDescriptor.getMojos() != null && pluginDescriptor.getMojos().size() > 0 ) )
425             {
426                 paragraph( getBundle( locale ).getString( "report.plugin.goals.nogoal" ) );
427                 endSection();
428                 return;
429             }
430 
431             paragraph( getBundle( locale ).getString( "report.plugin.goals.intro" ) );
432 
433             boolean hasMavenReport = false;
434             for ( Iterator<MojoDescriptor> i = pluginDescriptor.getMojos().iterator(); i.hasNext(); )
435             {
436                 MojoDescriptor mojo = i.next();
437 
438                 if ( GeneratorUtils.isMavenReport( mojo.getImplementation(), project ) )
439                 {
440                     hasMavenReport = true;
441                 }
442             }
443 
444             startTable();
445 
446             String goalColumnName = getBundle( locale ).getString( "report.plugin.goals.column.goal" );
447             String isMavenReport = getBundle( locale ).getString( "report.plugin.goals.column.isMavenReport" );
448             String descriptionColumnName = getBundle( locale ).getString( "report.plugin.goals.column.description" );
449             if ( hasMavenReport )
450             {
451                 tableHeader( new String[] {goalColumnName, isMavenReport, descriptionColumnName} );
452             }
453             else
454             {
455                 tableHeader( new String[] {goalColumnName, descriptionColumnName} );
456             }
457 
458             List<MojoDescriptor> mojos = new ArrayList<>();
459             mojos.addAll( pluginDescriptor.getMojos() );
460             PluginUtils.sortMojos( mojos );
461             for ( MojoDescriptor mojo : mojos )
462             {
463                 String goalName = mojo.getFullGoalName();
464 
465                 /*
466                  * Added ./ to define a relative path
467                  * @see AbstractMavenReportRenderer#getValidHref(java.lang.String)
468                  */
469                 String goalDocumentationLink = "./" + mojo.getGoal() + "-mojo.html";
470 
471                 String description;
472                 if ( StringUtils.isNotEmpty( mojo.getDeprecated() ) )
473                 {
474                     description =
475                         "<strong>" + getBundle( locale ).getString( "report.plugin.goal.deprecated" ) + "</strong> "
476                             + mojo.getDeprecated();
477                 }
478                 else if ( StringUtils.isNotEmpty( mojo.getDescription() ) )
479                 {
480                     description = mojo.getDescription();
481                 }
482                 else
483                 {
484                     description = getBundle( locale ).getString( "report.plugin.goal.nodescription" );
485                 }
486 
487                 sink.tableRow();
488                 tableCell( createLinkPatternedText( goalName, goalDocumentationLink ) );
489                 if ( hasMavenReport )
490                 {
491                     if ( GeneratorUtils.isMavenReport( mojo.getImplementation(), project ) )
492                     {
493                         sink.tableCell();
494                         sink.text( getBundle( locale ).getString( "report.plugin.isReport" ) );
495                         sink.tableCell_();
496                     }
497                     else
498                     {
499                         sink.tableCell();
500                         sink.text( getBundle( locale ).getString( "report.plugin.isNotReport" ) );
501                         sink.tableCell_();
502                     }
503                 }
504                 tableCell( description, true );
505                 sink.tableRow_();
506             }
507 
508             endTable();
509 
510             startSection( getBundle( locale ).getString( "report.plugin.systemrequirements" ) );
511 
512             paragraph( getBundle( locale ).getString( "report.plugin.systemrequirements.intro" ) );
513 
514             startTable();
515 
516             String maven = discoverMavenRequirement( project, requirements );
517             sink.tableRow();
518             tableCell( getBundle( locale ).getString( "report.plugin.systemrequirements.maven" ) );
519             tableCell( ( maven != null
520                 ? maven
521                 : getBundle( locale ).getString( "report.plugin.systemrequirements.nominimum" ) ) );
522             sink.tableRow_();
523 
524             String jdk = discoverJdkRequirement( project, requirements );
525             sink.tableRow();
526             tableCell( getBundle( locale ).getString( "report.plugin.systemrequirements.jdk" ) );
527             tableCell(
528                 ( jdk != null ? jdk : getBundle( locale ).getString( "report.plugin.systemrequirements.nominimum" ) ) );
529             sink.tableRow_();
530 
531             String memory = requirements.getMemory();
532             if ( StringUtils.isNotEmpty( memory ) )
533             {
534                 sink.tableRow();
535                 tableCell( getBundle( locale ).getString( "report.plugin.systemrequirements.memory" ) );
536                 tableCell( memory );
537                 sink.tableRow_();
538             }
539 
540             String diskSpace = requirements.getDiskSpace();
541             if ( StringUtils.isNotEmpty( diskSpace ) )
542             {
543                 sink.tableRow();
544                 tableCell( getBundle( locale ).getString( "report.plugin.systemrequirements.diskspace" ) );
545                 tableCell( diskSpace );
546                 sink.tableRow_();
547             }
548 
549             if ( requirements.getOthers() != null && requirements.getOthers().size() > 0 )
550             {
551                 for ( Iterator it = requirements.getOthers().keySet().iterator(); it.hasNext(); )
552                 {
553                     String key = it.next().toString();
554 
555                     sink.tableRow();
556                     tableCell( key );
557                     tableCell( ( StringUtils.isNotEmpty( requirements.getOthers().getProperty( key ) )
558                         ? requirements.getOthers().getProperty( key )
559                         : getBundle( locale ).getString( "report.plugin.systemrequirements.nominimum" ) ) );
560                     sink.tableRow_();
561                 }
562             }
563             endTable();
564 
565             endSection();
566 
567             renderRequirementsHistories();
568 
569             renderUsageSection( hasMavenReport );
570 
571             endSection();
572         }
573 
574         private void renderRequirementsHistories()
575         {
576             if ( requirementsHistories.isEmpty() )
577             {
578                 return;
579             }
580 
581             startSection( getBundle( locale ).getString( "report.plugin.systemrequirements.history" ) );
582             paragraph( getBundle( locale ).getString( "report.plugin.systemrequirements.history.intro" ) );
583 
584             startTable();
585             tableHeader( new String[] {
586                 getBundle( locale ).getString( "report.plugin.systemrequirements.history.version" ),
587                 getBundle( locale ).getString( "report.plugin.systemrequirements.history.maven" ),
588                 getBundle( locale ).getString( "report.plugin.systemrequirements.history.jdk" )
589             } );
590 
591             requirementsHistories.forEach(
592                 requirementsHistory ->
593                 {
594                     sink.tableRow();
595                     tableCell( requirementsHistory.getVersion() );
596                     tableCell( requirementsHistory.getMaven() );
597                     tableCell( requirementsHistory.getJdk() );
598                     sink.tableRow_();
599                 } );
600             endTable();
601 
602             endSection();
603         }
604 
605         /**
606          * Render the section about the usage of the plugin.
607          *
608          * @param hasMavenReport If the plugin has a report or not
609          */
610         private void renderUsageSection( boolean hasMavenReport )
611         {
612             startSection( getBundle( locale ).getString( "report.plugin.usage" ) );
613 
614             // Configuration
615             sink.paragraph();
616             text( getBundle( locale ).getString( "report.plugin.usage.intro" ) );
617             sink.paragraph_();
618 
619             StringBuilder sb = new StringBuilder();
620             sb.append( "<project>" ).append( '\n' );
621             sb.append( "  ..." ).append( '\n' );
622             sb.append( "  <build>" ).append( '\n' );
623             sb.append(
624                 "    <!-- " + getBundle( locale ).getString( "report.plugin.usage.pluginManagement" ) + " -->" ).append(
625                 '\n' );
626             sb.append( "    <pluginManagement>" ).append( '\n' );
627             sb.append( "      <plugins>" ).append( '\n' );
628             sb.append( "        <plugin>" ).append( '\n' );
629             sb.append( "          <groupId>" ).append( pluginDescriptor.getGroupId() ).append( "</groupId>" ).append(
630                 '\n' );
631             sb.append( "          <artifactId>" ).append( pluginDescriptor.getArtifactId() ).append(
632                 "</artifactId>" ).append( '\n' );
633             sb.append( "          <version>" ).append( pluginDescriptor.getVersion() ).append( "</version>" ).append(
634                 '\n' );
635             if ( hasExtensionsToLoad )
636             {
637                 sb.append( "          <extensions>true</extensions>" ).append(
638                     '\n' );
639             }
640             sb.append( "        </plugin>" ).append( '\n' );
641             sb.append( "        ..." ).append( '\n' );
642             sb.append( "      </plugins>" ).append( '\n' );
643             sb.append( "    </pluginManagement>" ).append( '\n' );
644             sb.append( "    <!-- " + getBundle( locale ).getString( "report.plugin.usage.plugins" ) + " -->" ).append(
645                 '\n' );
646             sb.append( "    <plugins>" ).append( '\n' );
647             sb.append( "      <plugin>" ).append( '\n' );
648             sb.append( "        <groupId>" ).append( pluginDescriptor.getGroupId() ).append( "</groupId>" ).append(
649                 '\n' );
650             sb.append( "        <artifactId>" ).append( pluginDescriptor.getArtifactId() ).append(
651                 "</artifactId>" ).append( '\n' );
652             sb.append( "      </plugin>" ).append( '\n' );
653             sb.append( "      ..." ).append( '\n' );
654             sb.append( "    </plugins>" ).append( '\n' );
655             sb.append( "  </build>" ).append( '\n' );
656 
657             if ( hasMavenReport )
658             {
659                 sb.append( "  ..." ).append( '\n' );
660                 sb.append(
661                     "  <!-- " + getBundle( locale ).getString( "report.plugin.usage.reporting" ) + " -->" ).append(
662                     '\n' );
663                 sb.append( "  <reporting>" ).append( '\n' );
664                 sb.append( "    <plugins>" ).append( '\n' );
665                 sb.append( "      <plugin>" ).append( '\n' );
666                 sb.append( "        <groupId>" ).append( pluginDescriptor.getGroupId() ).append( "</groupId>" ).append(
667                     '\n' );
668                 sb.append( "        <artifactId>" ).append( pluginDescriptor.getArtifactId() ).append(
669                     "</artifactId>" ).append( '\n' );
670                 sb.append( "        <version>" ).append( pluginDescriptor.getVersion() ).append( "</version>" ).append(
671                     '\n' );
672                 sb.append( "      </plugin>" ).append( '\n' );
673                 sb.append( "      ..." ).append( '\n' );
674                 sb.append( "    </plugins>" ).append( '\n' );
675                 sb.append( "  </reporting>" ).append( '\n' );
676             }
677 
678             sb.append( "  ..." ).append( '\n' );
679             sb.append( "</project>" ).append( '\n' );
680 
681             verbatimText( sb.toString() );
682 
683             sink.paragraph();
684             linkPatternedText( getBundle( locale ).getString( "report.plugin.configuration.end" ) );
685             sink.paragraph_();
686 
687             endSection();
688         }
689 
690         /**
691          * Try to lookup on the Maven prerequisites property.
692          * If not specified, uses the value defined by the user.
693          *
694          * @param project      not null
695          * @param requirements not null
696          * @return the Maven version
697          */
698         private static String discoverMavenRequirement( MavenProject project, Requirements requirements )
699         {
700             String maven = requirements.getMaven();
701             if ( maven == null )
702             {
703                 maven = ( project.getPrerequisites() != null ? project.getPrerequisites().getMaven() : null );
704             }
705             if ( maven == null )
706             {
707                 maven = "2.0";
708             }
709 
710             return maven;
711         }
712 
713         /**
714          * <ol>
715          * <li>use configured jdk requirement</li>
716          * <li>use <code>target</code> configuration of <code>org.apache.maven.plugins:maven-compiler-plugin</code></li>
717          * <li>use <code>target</code> configuration of <code>org.apache.maven.plugins:maven-compiler-plugin</code> in
718          * <code>pluginManagement</code></li>
719          * <li>use <code>maven.compiler.target</code> property</li>
720          * </ol>
721          *
722          * @param project      not null
723          * @param requirements not null
724          * @return the JDK version
725          */
726         private static String discoverJdkRequirement( MavenProject project, Requirements requirements )
727         {
728             String jdk = requirements.getJdk();
729 
730             if ( jdk != null )
731             {
732                 return jdk;
733             }
734 
735             Plugin compiler = getCompilerPlugin( project.getBuild().getPluginsAsMap() );
736             if ( compiler == null )
737             {
738                 compiler = getCompilerPlugin( project.getPluginManagement().getPluginsAsMap() );
739             }
740 
741             jdk = getPluginParameter( compiler, "release" );
742             if ( jdk != null )
743             {
744                 return jdk;
745             }
746 
747             jdk = project.getProperties().getProperty( "maven.compiler.release" );
748             if ( jdk != null )
749             {
750                 return jdk;
751             }
752 
753             jdk = getPluginParameter( compiler, "target" );
754             if ( jdk != null )
755             {
756                 return jdk;
757             }
758 
759             // default value
760             jdk = project.getProperties().getProperty( "maven.compiler.target" );
761             if ( jdk != null )
762             {
763                 return jdk;
764             }
765 
766             // return "1.5" by default?
767 
768             String version = ( compiler == null ) ? null : compiler.getVersion();
769 
770             if ( version != null )
771             {
772                 return "Default target for maven-compiler-plugin version " + version;
773             }
774 
775             return "Unknown";
776         }
777 
778         private static Plugin getCompilerPlugin( Map<String, Plugin> pluginsAsMap )
779         {
780             return pluginsAsMap.get( "org.apache.maven.plugins:maven-compiler-plugin" );
781         }
782 
783         private static String getPluginParameter( Plugin plugin, String parameter )
784         {
785             if ( plugin != null )
786             {
787                 Xpp3Dom pluginConf = (Xpp3Dom) plugin.getConfiguration();
788 
789                 if ( pluginConf != null )
790                 {
791                     Xpp3Dom target = pluginConf.getChild( parameter );
792 
793                     if ( target != null )
794                     {
795                         return target.getValue();
796                     }
797                 }
798             }
799 
800             return null;
801         }
802     }
803 }