View Javadoc
1   package org.apache.maven.plugin.plugin;
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 org.apache.maven.artifact.Artifact;
23  import org.apache.maven.artifact.repository.ArtifactRepository;
24  import org.apache.maven.doxia.sink.Sink;
25  import org.apache.maven.doxia.siterenderer.Renderer;
26  import org.apache.maven.model.Plugin;
27  import org.apache.maven.plugin.descriptor.InvalidPluginDescriptorException;
28  import org.apache.maven.plugin.descriptor.MojoDescriptor;
29  import org.apache.maven.plugin.descriptor.PluginDescriptor;
30  import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder;
31  import org.apache.maven.plugins.annotations.Component;
32  import org.apache.maven.plugins.annotations.Execute;
33  import org.apache.maven.plugins.annotations.LifecyclePhase;
34  import org.apache.maven.plugins.annotations.Mojo;
35  import org.apache.maven.plugins.annotations.Parameter;
36  import org.apache.maven.project.MavenProject;
37  import org.apache.maven.reporting.AbstractMavenReport;
38  import org.apache.maven.reporting.AbstractMavenReportRenderer;
39  import org.apache.maven.reporting.MavenReportException;
40  import org.apache.maven.tools.plugin.DefaultPluginToolsRequest;
41  import org.apache.maven.tools.plugin.PluginToolsRequest;
42  import org.apache.maven.tools.plugin.extractor.ExtractionException;
43  import org.apache.maven.tools.plugin.generator.GeneratorException;
44  import org.apache.maven.tools.plugin.generator.GeneratorUtils;
45  import org.apache.maven.tools.plugin.generator.PluginXdocGenerator;
46  import org.apache.maven.tools.plugin.scanner.MojoScanner;
47  import org.apache.maven.tools.plugin.util.PluginUtils;
48  import org.codehaus.plexus.component.repository.ComponentDependency;
49  import org.codehaus.plexus.configuration.PlexusConfigurationException;
50  import org.codehaus.plexus.util.StringUtils;
51  import org.codehaus.plexus.util.xml.Xpp3Dom;
52  
53  import java.io.File;
54  import java.io.FileNotFoundException;
55  import java.io.FileReader;
56  import java.util.ArrayList;
57  import java.util.Iterator;
58  import java.util.List;
59  import java.util.Locale;
60  import java.util.Map;
61  import java.util.ResourceBundle;
62  import java.util.Set;
63  
64  /**
65   * Generates the Plugin's documentation report: <code>plugin-info.html</code> plugin overview page,
66   * and one <code><i>goal</i>-mojo.html</code> per goal.
67   *
68   * @author <a href="snicoll@apache.org">Stephane Nicoll</a>
69   * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
70   * @version $Id: PluginReport.html 995996 2016-08-26 22:31:42Z rfscholte $
71   * @since 2.0
72   */
73  @Mojo( name = "report", threadSafe = true )
74  @Execute( phase = LifecyclePhase.PROCESS_CLASSES )
75  public class PluginReport
76      extends AbstractMavenReport
77  {
78      /**
79       * Report output directory for mojos' documentation.
80       */
81      @Parameter( defaultValue = "${project.build.directory}/generated-site/xdoc" )
82      private File outputDirectory;
83  
84      /**
85       * Doxia Site Renderer.
86       */
87      @Component
88      private Renderer siteRenderer;
89  
90      /**
91       * The Maven Project.
92       */
93      @Parameter( defaultValue = "${project}", readonly = true )
94      private MavenProject project;
95  
96      /**
97       * Mojo scanner tools.
98       */
99      @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      * &lt;requirements&gt;
115      *   &lt;maven&gt;2.0&lt;/maven&gt;
116      *   &lt;jdk&gt;1.4&lt;/jdk&gt;
117      *   &lt;memory&gt;256m&lt;/memory&gt;
118      *   &lt;diskSpace&gt;1m&lt;/diskSpace&gt;
119      *   &lt;others&gt;
120      *     &lt;property&gt;
121      *       &lt;name&gt;SVN&lt;/name&gt;
122      *       &lt;value&gt;1.4.6&lt;/value&gt;
123      *     &lt;/property&gt;
124      *   &lt;/others&gt;
125      * &lt;/requirements&gt;
126      * </pre>
127      */
128     @Parameter
129     private Requirements requirements;
130 
131     /**
132      * The goal prefix that will appear before the ":".
133      * By default, this plugin applies a heuristic to derive a heuristic from
134      * the plugin's artifactId.
135      * <p/>
136      * It removes any occurrences of the regular expression <strong>-?maven-?</strong>,
137      * and then removes any occurrences of <strong>-?plugin-?</strong>.
138      * <p>
139      * For example, horsefeature-maven-plugin becomes horsefeature.
140      * </p>
141      * <p>
142      * (There is a special for maven-plugin-plugin; it is mapped to 'plugin'.
143      * </p>
144      *
145      * @since 2.4
146      */
147     @Parameter( property = "goalPrefix" )
148     protected String goalPrefix;
149 
150     /**
151      * Set this to "true" to skip invoking any goals or reports of the plugin.
152      *
153      * @since 2.8
154      */
155     @Parameter( defaultValue = "false", property = "maven.plugin.skip" )
156     private boolean skip;
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 skipReport;
165 
166     /**
167      * The set of dependencies for the current project
168      *
169      * @since 3.0
170      */
171     @Parameter( defaultValue = "${project.artifacts}", required = true, readonly = true )
172     protected Set<Artifact> dependencies;
173 
174     /**
175      * List of Remote Repositories used by the resolver
176      *
177      * @since 3.0
178      */
179     @Parameter( defaultValue = "${project.remoteArtifactRepositories}", required = true, readonly = true )
180     protected List<ArtifactRepository> remoteRepos;
181 
182     /**
183      * Location of the local repository.
184      *
185      * @since 3.0
186      */
187     @Parameter( defaultValue = "${localRepository}", required = true, readonly = true )
188     protected ArtifactRepository local;
189 
190     /**
191      * {@inheritDoc}
192      */
193     protected Renderer getSiteRenderer()
194     {
195         return siteRenderer;
196     }
197 
198     /**
199      * {@inheritDoc}
200      */
201     protected String getOutputDirectory()
202     {
203         // PLUGIN-191: output directory of plugin.html, not *-mojo.xml
204         return project.getReporting().getOutputDirectory();
205     }
206 
207     /**
208      * {@inheritDoc}
209      */
210     protected MavenProject getProject()
211     {
212         return project;
213     }
214 
215     /**
216      * {@inheritDoc}
217      */
218     public boolean canGenerateReport()
219     {
220         return "maven-plugin".equals( project.getPackaging() );
221     }
222 
223     /**
224      * {@inheritDoc}
225      */
226     protected void executeReport( Locale locale )
227         throws MavenReportException
228     {
229         if ( !canGenerateReport() )
230         {
231             return;
232         }
233         if ( skip || skipReport )
234         {
235             getLog().info( "Maven Plugin Plugin Report generation skipped." );
236             return;
237         }
238 
239         PluginDescriptor pluginDescriptor = extractPluginDescriptor();
240 
241         // Generate the mojos' documentation
242         generateMojosDocumentation( pluginDescriptor, locale );
243 
244         // Write the overview
245         PluginOverviewRenderer r =
246             new PluginOverviewRenderer( project, requirements, getSink(), pluginDescriptor, locale );
247         r.render();
248     }
249 
250     private PluginDescriptor extractPluginDescriptor()
251         throws MavenReportException
252     {
253         PluginDescriptorBuilder builder = new PluginDescriptorBuilder();
254         try
255         {
256             return builder.build( new FileReader( new File( project.getBuild().getOutputDirectory(),
257                                                             "META-INF/maven/plugin.xml" ) ) );
258         }
259         catch ( FileNotFoundException e )
260         {
261             getLog().debug( "Failed to read META-INF/maven/plugin.xml, fall back to mojoScanner" );
262         }
263         catch ( PlexusConfigurationException e )
264         {
265             getLog().debug( "Failed to read META-INF/maven/plugin.xml, fall back to mojoScanner" );
266         }
267 
268         // Copy from AbstractGeneratorMojo#execute()
269         String defaultGoalPrefix = PluginDescriptor.getGoalPrefixFromArtifactId( project.getArtifactId() );
270         if ( goalPrefix == null )
271         {
272             goalPrefix = defaultGoalPrefix;
273         }
274         else
275         {
276             getLog().warn( "\n\nGoal prefix is specified as: '" + goalPrefix + "'. Maven currently expects it to be '"
277                                + defaultGoalPrefix + "'.\n" );
278         }
279 
280         // TODO: could use this more, eg in the writing of the plugin descriptor!
281         PluginDescriptor pluginDescriptor = new PluginDescriptor();
282 
283         pluginDescriptor.setGroupId( project.getGroupId() );
284 
285         pluginDescriptor.setArtifactId( project.getArtifactId() );
286 
287         pluginDescriptor.setVersion( project.getVersion() );
288 
289         pluginDescriptor.setGoalPrefix( goalPrefix );
290 
291         try
292         {
293             @SuppressWarnings( "unchecked" )
294             List<ComponentDependency> deps = GeneratorUtils.toComponentDependencies( project.getRuntimeDependencies() );
295             pluginDescriptor.setDependencies( deps );
296 
297             PluginToolsRequest request = new DefaultPluginToolsRequest( project, pluginDescriptor );
298             request.setEncoding( encoding );
299             request.setSkipErrorNoDescriptorsFound( true );
300             request.setDependencies( dependencies );
301             request.setLocal( this.local );
302             request.setRemoteRepos( this.remoteRepos );
303 
304             try
305             {
306                 mojoScanner.populatePluginDescriptor( request );
307             }
308             catch ( InvalidPluginDescriptorException e )
309             {
310                 // this is OK, it happens to lifecycle plugins. Allow generation to proceed.
311                 getLog().debug( "Plugin without mojos.", e );
312             }
313         }
314         catch ( ExtractionException e )
315         {
316             throw new MavenReportException( "Error extracting plugin descriptor: \'" + e.getLocalizedMessage() + "\'",
317                                             e );
318         }
319         return pluginDescriptor;
320     }
321 
322     /**
323      * {@inheritDoc}
324      */
325     public String getDescription( Locale locale )
326     {
327         return getBundle( locale ).getString( "report.plugin.description" );
328     }
329 
330     /**
331      * {@inheritDoc}
332      */
333     public String getName( Locale locale )
334     {
335         return getBundle( locale ).getString( "report.plugin.name" );
336     }
337 
338     /**
339      * {@inheritDoc}
340      */
341     public String getOutputName()
342     {
343         return "plugin-info";
344     }
345 
346     /**
347      * Generate the mojos documentation, as xdoc files.
348      *
349      * @param pluginDescriptor not null
350      * @param locale           not null
351      * @throws MavenReportException if any
352      */
353     private void generateMojosDocumentation( PluginDescriptor pluginDescriptor, Locale locale )
354         throws MavenReportException
355     {
356         try
357         {
358             File outputDir = outputDirectory;
359             outputDir.mkdirs();
360 
361             PluginXdocGenerator generator = new PluginXdocGenerator( project, locale );
362             PluginToolsRequest pluginToolsRequest = new DefaultPluginToolsRequest( project, pluginDescriptor );
363             generator.execute( outputDir, pluginToolsRequest );
364         }
365         catch ( GeneratorException e )
366         {
367             throw new MavenReportException( "Error writing plugin documentation", e );
368         }
369 
370     }
371 
372     /**
373      * @param locale not null
374      * @return the bundle for this report
375      */
376     protected static ResourceBundle getBundle( Locale locale )
377     {
378         return ResourceBundle.getBundle( "plugin-report", locale, PluginReport.class.getClassLoader() );
379     }
380 
381     /**
382      * Generates an overview page with the list of goals
383      * and a link to the goal's page.
384      */
385     static class PluginOverviewRenderer
386         extends AbstractMavenReportRenderer
387     {
388         private final MavenProject project;
389 
390         private final Requirements requirements;
391 
392         private final PluginDescriptor pluginDescriptor;
393 
394         private final Locale locale;
395 
396         /**
397          * @param project          not null
398          * @param requirements     not null
399          * @param sink             not null
400          * @param pluginDescriptor not null
401          * @param locale           not null
402          */
403         public PluginOverviewRenderer( MavenProject project, Requirements requirements, Sink sink,
404                                        PluginDescriptor pluginDescriptor, Locale locale )
405         {
406             super( sink );
407 
408             this.project = project;
409 
410             this.requirements = ( requirements == null ? new Requirements() : requirements );
411 
412             this.pluginDescriptor = pluginDescriptor;
413 
414             this.locale = locale;
415         }
416 
417         /**
418          * {@inheritDoc}
419          */
420         public String getTitle()
421         {
422             return getBundle( locale ).getString( "report.plugin.title" );
423         }
424 
425         /**
426          * {@inheritDoc}
427          */
428         @SuppressWarnings( { "unchecked", "rawtypes" } )
429         public void renderBody()
430         {
431             startSection( getTitle() );
432 
433             if ( !( pluginDescriptor.getMojos() != null && pluginDescriptor.getMojos().size() > 0 ) )
434             {
435                 paragraph( getBundle( locale ).getString( "report.plugin.goals.nogoal" ) );
436                 endSection();
437                 return;
438             }
439 
440             paragraph( getBundle( locale ).getString( "report.plugin.goals.intro" ) );
441 
442             boolean hasMavenReport = false;
443             for ( Iterator<MojoDescriptor> i = pluginDescriptor.getMojos().iterator(); i.hasNext(); )
444             {
445                 MojoDescriptor mojo = i.next();
446 
447                 if ( GeneratorUtils.isMavenReport( mojo.getImplementation(), project ) )
448                 {
449                     hasMavenReport = true;
450                 }
451             }
452 
453             startTable();
454 
455             String goalColumnName = getBundle( locale ).getString( "report.plugin.goals.column.goal" );
456             String isMavenReport = getBundle( locale ).getString( "report.plugin.goals.column.isMavenReport" );
457             String descriptionColumnName = getBundle( locale ).getString( "report.plugin.goals.column.description" );
458             if ( hasMavenReport )
459             {
460                 tableHeader( new String[]{ goalColumnName, isMavenReport, descriptionColumnName } );
461             }
462             else
463             {
464                 tableHeader( new String[]{ goalColumnName, descriptionColumnName } );
465             }
466 
467             List<MojoDescriptor> mojos = new ArrayList<MojoDescriptor>();
468             mojos.addAll( pluginDescriptor.getMojos() );
469             PluginUtils.sortMojos( mojos );
470             for ( MojoDescriptor mojo : mojos )
471             {
472                 String goalName = mojo.getFullGoalName();
473 
474                 /*
475                  * Added ./ to define a relative path
476                  * @see AbstractMavenReportRenderer#getValidHref(java.lang.String)
477                  */
478                 String goalDocumentationLink = "./" + mojo.getGoal() + "-mojo.html";
479 
480                 String description;
481                 if ( StringUtils.isNotEmpty( mojo.getDeprecated() ) )
482                 {
483                     description =
484                         "<strong>" + getBundle( locale ).getString( "report.plugin.goal.deprecated" ) + "</strong> "
485                             + GeneratorUtils.makeHtmlValid( mojo.getDeprecated() );
486                 }
487                 else if ( StringUtils.isNotEmpty( mojo.getDescription() ) )
488                 {
489                     description = GeneratorUtils.makeHtmlValid( mojo.getDescription() );
490                 }
491                 else
492                 {
493                     description = getBundle( locale ).getString( "report.plugin.goal.nodescription" );
494                 }
495 
496                 sink.tableRow();
497                 tableCell( createLinkPatternedText( goalName, goalDocumentationLink ) );
498                 if ( hasMavenReport )
499                 {
500                     if ( GeneratorUtils.isMavenReport( mojo.getImplementation(), project ) )
501                     {
502                         sink.tableCell();
503                         sink.text( getBundle( locale ).getString( "report.plugin.isReport" ) );
504                         sink.tableCell_();
505                     }
506                     else
507                     {
508                         sink.tableCell();
509                         sink.text( getBundle( locale ).getString( "report.plugin.isNotReport" ) );
510                         sink.tableCell_();
511                     }
512                 }
513                 tableCell( description, true );
514                 sink.tableRow_();
515             }
516 
517             endTable();
518 
519             startSection( getBundle( locale ).getString( "report.plugin.systemrequirements" ) );
520 
521             paragraph( getBundle( locale ).getString( "report.plugin.systemrequirements.intro" ) );
522 
523             startTable();
524 
525             String maven = discoverMavenRequirement( project, requirements );
526             sink.tableRow();
527             tableCell( getBundle( locale ).getString( "report.plugin.systemrequirements.maven" ) );
528             tableCell( ( maven != null
529                 ? maven
530                 : getBundle( locale ).getString( "report.plugin.systemrequirements.nominimum" ) ) );
531             sink.tableRow_();
532 
533             String jdk = discoverJdkRequirement( project, requirements );
534             sink.tableRow();
535             tableCell( getBundle( locale ).getString( "report.plugin.systemrequirements.jdk" ) );
536             tableCell(
537                 ( jdk != null ? jdk : getBundle( locale ).getString( "report.plugin.systemrequirements.nominimum" ) ) );
538             sink.tableRow_();
539 
540             sink.tableRow();
541             tableCell( getBundle( locale ).getString( "report.plugin.systemrequirements.memory" ) );
542             tableCell( ( StringUtils.isNotEmpty( requirements.getMemory() )
543                 ? requirements.getMemory()
544                 : getBundle( locale ).getString( "report.plugin.systemrequirements.nominimum" ) ) );
545             sink.tableRow_();
546 
547             sink.tableRow();
548             tableCell( getBundle( locale ).getString( "report.plugin.systemrequirements.diskspace" ) );
549             tableCell( ( StringUtils.isNotEmpty( requirements.getDiskSpace() )
550                 ? requirements.getDiskSpace()
551                 : getBundle( locale ).getString( "report.plugin.systemrequirements.nominimum" ) ) );
552             sink.tableRow_();
553 
554             if ( requirements.getOthers() != null && requirements.getOthers().size() > 0 )
555             {
556                 for ( Iterator it = requirements.getOthers().keySet().iterator(); it.hasNext(); )
557                 {
558                     String key = it.next().toString();
559 
560                     sink.tableRow();
561                     tableCell( key );
562                     tableCell( ( StringUtils.isNotEmpty( requirements.getOthers().getProperty( key ) )
563                         ? requirements.getOthers().getProperty( key )
564                         : getBundle( locale ).getString( "report.plugin.systemrequirements.nominimum" ) ) );
565                     sink.tableRow_();
566                 }
567             }
568             endTable();
569 
570             endSection();
571 
572             renderUsageSection( hasMavenReport );
573 
574             endSection();
575         }
576 
577         /**
578          * Render the section about the usage of the plugin.
579          *
580          * @param hasMavenReport If the plugin has a report or not
581          */
582         private void renderUsageSection( boolean hasMavenReport )
583         {
584             startSection( getBundle( locale ).getString( "report.plugin.usage" ) );
585 
586             // Configuration
587             sink.paragraph();
588             text( getBundle( locale ).getString( "report.plugin.usage.intro" ) );
589             sink.paragraph_();
590 
591             StringBuilder sb = new StringBuilder();
592             sb.append( "<project>" ).append( '\n' );
593             sb.append( "  ..." ).append( '\n' );
594             sb.append( "  <build>" ).append( '\n' );
595             sb.append(
596                 "    <!-- " + getBundle( locale ).getString( "report.plugin.usage.pluginManagement" ) + " -->" ).append(
597                 '\n' );
598             sb.append( "    <pluginManagement>" ).append( '\n' );
599             sb.append( "      <plugins>" ).append( '\n' );
600             sb.append( "        <plugin>" ).append( '\n' );
601             sb.append( "          <groupId>" ).append( pluginDescriptor.getGroupId() ).append( "</groupId>" ).append(
602                 '\n' );
603             sb.append( "          <artifactId>" ).append( pluginDescriptor.getArtifactId() ).append(
604                 "</artifactId>" ).append( '\n' );
605             sb.append( "          <version>" ).append( pluginDescriptor.getVersion() ).append( "</version>" ).append(
606                 '\n' );
607             sb.append( "        </plugin>" ).append( '\n' );
608             sb.append( "        ..." ).append( '\n' );
609             sb.append( "      </plugins>" ).append( '\n' );
610             sb.append( "    </pluginManagement>" ).append( '\n' );
611             sb.append( "    <!-- " + getBundle( locale ).getString( "report.plugin.usage.plugins" ) + " -->" ).append(
612                 '\n' );
613             sb.append( "    <plugins>" ).append( '\n' );
614             sb.append( "      <plugin>" ).append( '\n' );
615             sb.append( "        <groupId>" ).append( pluginDescriptor.getGroupId() ).append( "</groupId>" ).append(
616                 '\n' );
617             sb.append( "        <artifactId>" ).append( pluginDescriptor.getArtifactId() ).append(
618                 "</artifactId>" ).append( '\n' );
619             sb.append( "        <version>" ).append( pluginDescriptor.getVersion() ).append( "</version>" ).append(
620                 '\n' );
621             sb.append( "      </plugin>" ).append( '\n' );
622             sb.append( "      ..." ).append( '\n' );
623             sb.append( "    </plugins>" ).append( '\n' );
624             sb.append( "  </build>" ).append( '\n' );
625 
626             if ( hasMavenReport )
627             {
628                 sb.append( "  ..." ).append( '\n' );
629                 sb.append(
630                     "  <!-- " + getBundle( locale ).getString( "report.plugin.usage.reporting" ) + " -->" ).append(
631                     '\n' );
632                 sb.append( "  <reporting>" ).append( '\n' );
633                 sb.append( "    <plugins>" ).append( '\n' );
634                 sb.append( "      <plugin>" ).append( '\n' );
635                 sb.append( "        <groupId>" ).append( pluginDescriptor.getGroupId() ).append( "</groupId>" ).append(
636                     '\n' );
637                 sb.append( "        <artifactId>" ).append( pluginDescriptor.getArtifactId() ).append(
638                     "</artifactId>" ).append( '\n' );
639                 sb.append( "        <version>" ).append( pluginDescriptor.getVersion() ).append( "</version>" ).append(
640                     '\n' );
641                 sb.append( "      </plugin>" ).append( '\n' );
642                 sb.append( "      ..." ).append( '\n' );
643                 sb.append( "    </plugins>" ).append( '\n' );
644                 sb.append( "  </reporting>" ).append( '\n' );
645             }
646 
647             sb.append( "  ..." ).append( '\n' );
648             sb.append( "</project>" ).append( '\n' );
649 
650             verbatimText( sb.toString() );
651 
652             sink.paragraph();
653             linkPatternedText( getBundle( locale ).getString( "report.plugin.configuration.end" ) );
654             sink.paragraph_();
655 
656             endSection();
657         }
658 
659         /**
660          * Try to lookup on the Maven prerequisites property.
661          * If not specified, uses the value defined by the user.
662          *
663          * @param project      not null
664          * @param requirements not null
665          * @return the Maven version
666          */
667         private static String discoverMavenRequirement( MavenProject project, Requirements requirements )
668         {
669             String maven = requirements.getMaven();
670             if ( maven == null )
671             {
672                 maven = ( project.getPrerequisites() != null ? project.getPrerequisites().getMaven() : null );
673             }
674             if ( maven == null )
675             {
676                 maven = "2.0";
677             }
678 
679             return maven;
680         }
681 
682         /**
683          * <ol>
684          * <li>use configured jdk requirement</li>
685          * <li>use <code>target</code> configuration of <code>org.apache.maven.plugins:maven-compiler-plugin</code></li>
686          * <li>use <code>target</code> configuration of <code>org.apache.maven.plugins:maven-compiler-plugin</code> in
687          * <code>pluginManagement</code></li>
688          * <li>use <code>maven.compiler.target</code> property</li>
689          * </ol>
690          *
691          * @param project      not null
692          * @param requirements not null
693          * @return the JDK version
694          */
695         private static String discoverJdkRequirement( MavenProject project, Requirements requirements )
696         {
697             String jdk = requirements.getJdk();
698 
699             if ( jdk != null )
700             {
701                 return jdk;
702             }
703 
704             @SuppressWarnings( "unchecked" )
705             Plugin compiler = getCompilerPlugin( project.getBuild().getPluginsAsMap() );
706             if ( compiler == null )
707             {
708                 compiler = getCompilerPlugin( project.getPluginManagement().getPluginsAsMap() );
709             }
710 
711             jdk = getPluginParameter( compiler, "target" );
712             if ( jdk != null )
713             {
714                 return jdk;
715             }
716 
717             // default value
718             jdk = project.getProperties().getProperty( "maven.compiler.target" );
719             if ( jdk != null )
720             {
721                 return jdk;
722             }
723 
724             // return "1.5" by default?
725 
726             String version = ( compiler == null ) ? null : compiler.getVersion();
727 
728             if ( version != null )
729             {
730                 return "Default target for maven-compiler-plugin version " + version;
731             }
732 
733             return "Unknown";
734         }
735 
736         private static Plugin getCompilerPlugin( Map<String, Object> pluginsAsMap )
737         {
738             return (Plugin) pluginsAsMap.get( "org.apache.maven.plugins:maven-compiler-plugin" );
739         }
740 
741         private static String getPluginParameter( Plugin plugin, String parameter )
742         {
743             if ( plugin != null )
744             {
745                 Xpp3Dom pluginConf = (Xpp3Dom) plugin.getConfiguration();
746 
747                 if ( pluginConf != null )
748                 {
749                     Xpp3Dom target = pluginConf.getChild( parameter );
750 
751                     if ( target != null )
752                     {
753                         return target.getValue();
754                     }
755                 }
756             }
757 
758             return null;
759         }
760     }
761 }