View Javadoc

1   package org.apache.maven.tools.plugin.annotations;
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 com.thoughtworks.qdox.JavaDocBuilder;
23  import com.thoughtworks.qdox.model.DocletTag;
24  import com.thoughtworks.qdox.model.JavaClass;
25  import com.thoughtworks.qdox.model.JavaField;
26  import org.apache.maven.artifact.Artifact;
27  import org.apache.maven.artifact.factory.ArtifactFactory;
28  import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
29  import org.apache.maven.artifact.resolver.ArtifactResolutionException;
30  import org.apache.maven.artifact.resolver.ArtifactResolver;
31  import org.apache.maven.plugin.descriptor.DuplicateParameterException;
32  import org.apache.maven.plugin.descriptor.InvalidParameterException;
33  import org.apache.maven.plugin.descriptor.InvalidPluginDescriptorException;
34  import org.apache.maven.plugin.descriptor.MojoDescriptor;
35  import org.apache.maven.plugin.descriptor.PluginDescriptor;
36  import org.apache.maven.plugin.descriptor.Requirement;
37  import org.apache.maven.project.MavenProject;
38  import org.apache.maven.tools.plugin.DefaultPluginToolsRequest;
39  import org.apache.maven.tools.plugin.ExtendedMojoDescriptor;
40  import org.apache.maven.tools.plugin.PluginToolsRequest;
41  import org.apache.maven.tools.plugin.annotations.datamodel.ComponentAnnotationContent;
42  import org.apache.maven.tools.plugin.annotations.datamodel.ExecuteAnnotationContent;
43  import org.apache.maven.tools.plugin.annotations.datamodel.MojoAnnotationContent;
44  import org.apache.maven.tools.plugin.annotations.datamodel.ParameterAnnotationContent;
45  import org.apache.maven.tools.plugin.annotations.scanner.MojoAnnotatedClass;
46  import org.apache.maven.tools.plugin.annotations.scanner.MojoAnnotationsScanner;
47  import org.apache.maven.tools.plugin.annotations.scanner.MojoAnnotationsScannerRequest;
48  import org.apache.maven.tools.plugin.extractor.ExtractionException;
49  import org.apache.maven.tools.plugin.extractor.MojoDescriptorExtractor;
50  import org.apache.maven.tools.plugin.util.PluginUtils;
51  import org.codehaus.plexus.archiver.UnArchiver;
52  import org.codehaus.plexus.archiver.manager.ArchiverManager;
53  import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
54  import org.codehaus.plexus.component.annotations.Component;
55  import org.codehaus.plexus.logging.AbstractLogEnabled;
56  import org.codehaus.plexus.util.StringUtils;
57  
58  import java.io.File;
59  import java.util.ArrayList;
60  import java.util.Arrays;
61  import java.util.Collection;
62  import java.util.Collections;
63  import java.util.HashMap;
64  import java.util.HashSet;
65  import java.util.List;
66  import java.util.Map;
67  import java.util.Set;
68  import java.util.TreeMap;
69  import java.util.TreeSet;
70  
71  /**
72   * JavaMojoDescriptorExtractor, a MojoDescriptor extractor to read descriptors from java classes with annotations.
73   *
74   * @author Olivier Lamy
75   * @since 3.0
76   */
77  @Component( role = MojoDescriptorExtractor.class, hint = "java-annotations" )
78  public class JavaAnnotationsMojoDescriptorExtractor
79      extends AbstractLogEnabled
80      implements MojoDescriptorExtractor
81  {
82  
83      @org.codehaus.plexus.component.annotations.Requirement
84      private MojoAnnotationsScanner mojoAnnotationsScanner;
85  
86      @org.codehaus.plexus.component.annotations.Requirement
87      private ArtifactResolver artifactResolver;
88  
89      @org.codehaus.plexus.component.annotations.Requirement
90      private ArtifactFactory artifactFactory;
91  
92      @org.codehaus.plexus.component.annotations.Requirement
93      private ArchiverManager archiverManager;
94  
95      public List<MojoDescriptor> execute( MavenProject project, PluginDescriptor pluginDescriptor )
96          throws ExtractionException, InvalidPluginDescriptorException
97      {
98          return execute( new DefaultPluginToolsRequest( project, pluginDescriptor ) );
99      }
100 
101     public List<MojoDescriptor> execute( PluginToolsRequest request )
102         throws ExtractionException, InvalidPluginDescriptorException
103     {
104         Map<String, MojoAnnotatedClass> mojoAnnotatedClasses = scanAnnotations( request );
105 
106         Map<String, JavaClass> javaClassesMap = scanJavadoc( request, mojoAnnotatedClasses.values() );
107 
108         populateDataFromJavadoc( mojoAnnotatedClasses, javaClassesMap );
109 
110         return toMojoDescriptors( mojoAnnotatedClasses, request.getPluginDescriptor() );
111     }
112 
113     private Map<String, MojoAnnotatedClass> scanAnnotations( PluginToolsRequest request )
114         throws ExtractionException
115     {
116         MojoAnnotationsScannerRequest mojoAnnotationsScannerRequest = new MojoAnnotationsScannerRequest();
117 
118         File output = new File( request.getProject().getBuild().getOutputDirectory() );
119         mojoAnnotationsScannerRequest.setClassesDirectories( Arrays.asList( output ) );
120 
121         mojoAnnotationsScannerRequest.setDependencies( request.getDependencies() );
122 
123         mojoAnnotationsScannerRequest.setProject( request.getProject() );
124 
125         return mojoAnnotationsScanner.scan( mojoAnnotationsScannerRequest );
126     }
127 
128     private Map<String, JavaClass> scanJavadoc( PluginToolsRequest request,
129                                                 Collection<MojoAnnotatedClass> mojoAnnotatedClasses )
130         throws ExtractionException
131     {
132         // found artifact from reactors to scan sources
133         // we currently only scan sources from reactors
134         List<MavenProject> mavenProjects = new ArrayList<MavenProject>();
135 
136         // if we need to scan sources from external artifacts
137         Set<Artifact> externalArtifacts = new HashSet<Artifact>();
138 
139         for ( MojoAnnotatedClass mojoAnnotatedClass : mojoAnnotatedClasses )
140         {
141             if ( StringUtils.equals( mojoAnnotatedClass.getArtifact().getArtifactId(),
142                                      request.getProject().getArtifact().getArtifactId() ) )
143             {
144                 continue;
145             }
146 
147             if ( !isMojoAnnnotatedClassCandidate( mojoAnnotatedClass ) )
148             {
149                 // we don't scan sources for classes without mojo annotations
150                 continue;
151             }
152 
153             MavenProject mavenProject =
154                 getFromProjectReferences( mojoAnnotatedClass.getArtifact(), request.getProject() );
155 
156             if ( mavenProject != null )
157             {
158                 mavenProjects.add( mavenProject );
159             }
160             else
161             {
162                 externalArtifacts.add( mojoAnnotatedClass.getArtifact() );
163             }
164         }
165 
166         Map<String, JavaClass> javaClassesMap = new HashMap<String, JavaClass>();
167 
168         // try to get artifact with sources classifier, extract somewhere then scan for @since, @deprecated
169         for ( Artifact artifact : externalArtifacts )
170         {
171             // parameter for test-sources too ?? olamy I need that for it test only
172             if ( StringUtils.equalsIgnoreCase( "tests", artifact.getClassifier() ) )
173             {
174                 javaClassesMap.putAll( discoverClassesFromSourcesJar( artifact, request, "test-sources" ) );
175             }
176             else
177             {
178                 javaClassesMap.putAll( discoverClassesFromSourcesJar( artifact, request, "sources" ) );
179             }
180 
181         }
182 
183         for ( MavenProject mavenProject : mavenProjects )
184         {
185             javaClassesMap.putAll( discoverClasses( request.getEncoding(), mavenProject ) );
186         }
187 
188         javaClassesMap.putAll( discoverClasses( request ) );
189 
190         return javaClassesMap;
191     }
192 
193     private boolean isMojoAnnnotatedClassCandidate( MojoAnnotatedClass mojoAnnotatedClass )
194     {
195         if ( mojoAnnotatedClass == null )
196         {
197             return false;
198         }
199         return ( !mojoAnnotatedClass.getComponents().isEmpty() || !mojoAnnotatedClass.getParameters().isEmpty()
200             || mojoAnnotatedClass.getExecute() != null || mojoAnnotatedClass.getMojo() != null );
201 
202     }
203 
204     protected Map<String, JavaClass> discoverClassesFromSourcesJar( Artifact artifact, PluginToolsRequest request,
205                                                                     String classifier )
206         throws ExtractionException
207     {
208         try
209         {
210             Artifact sourcesArtifact =
211                 artifactFactory.createArtifactWithClassifier( artifact.getGroupId(), artifact.getArtifactId(),
212                                                               artifact.getVersion(), artifact.getType(), classifier );
213 
214             artifactResolver.resolve( sourcesArtifact, request.getRemoteRepos(), request.getLocal() );
215 
216             if ( sourcesArtifact.getFile() == null || !sourcesArtifact.getFile().exists() )
217             {
218                 // could not get artifact sources
219                 return Collections.emptyMap();
220             }
221 
222             // extract sources to target/maven-plugin-plugin-sources/${groupId}/${artifact}/sources
223             File extractDirectory = new File( request.getProject().getBuild().getDirectory(),
224                                               "maven-plugin-plugin-sources/" + sourcesArtifact.getGroupId() + "/"
225                                                   + sourcesArtifact.getArtifactId() + "/" + sourcesArtifact.getVersion()
226                                                   + "/" + sourcesArtifact.getClassifier() );
227             extractDirectory.mkdirs();
228 
229             UnArchiver unArchiver = archiverManager.getUnArchiver( "jar" );
230             unArchiver.setSourceFile( sourcesArtifact.getFile() );
231             unArchiver.setDestDirectory( extractDirectory );
232             unArchiver.extract();
233 
234             return discoverClasses( request.getEncoding(), Arrays.asList( extractDirectory ) );
235         }
236         catch ( ArtifactResolutionException e )
237         {
238             throw new ExtractionException( e.getMessage(), e );
239         }
240         catch ( ArtifactNotFoundException e )
241         {
242             //throw new ExtractionException( e.getMessage(), e );
243             getLogger().debug( "skip ArtifactNotFoundException:" + e.getMessage() );
244             getLogger().warn(
245                 "Unable to get sources artifact for " + artifact.getGroupId() + ":" + artifact.getArtifactId() + ":"
246                     + artifact.getVersion() + ". Some javadoc tags (@since, @deprecated and comments) won't be used" );
247             return Collections.emptyMap();
248         }
249         catch ( NoSuchArchiverException e )
250         {
251             throw new ExtractionException( e.getMessage(), e );
252         }
253     }
254 
255     /**
256      * from sources scan to get @since and @deprecated and description of classes and fields.
257      *
258      * @param mojoAnnotatedClasses
259      * @param javaClassesMap
260      */
261     protected void populateDataFromJavadoc( Map<String, MojoAnnotatedClass> mojoAnnotatedClasses,
262                                             Map<String, JavaClass> javaClassesMap )
263     {
264 
265         for ( Map.Entry<String, MojoAnnotatedClass> entry : mojoAnnotatedClasses.entrySet() )
266         {
267             JavaClass javaClass = javaClassesMap.get( entry.getKey() );
268             if ( javaClass == null )
269             {
270                 continue;
271             }
272 
273             // populate class-level content
274             MojoAnnotationContent mojoAnnotationContent = entry.getValue().getMojo();
275             if ( mojoAnnotationContent != null )
276             {
277                 mojoAnnotationContent.setDescription( javaClass.getComment() );
278 
279                 DocletTag since = findInClassHierarchy( javaClass, "since" );
280                 if ( since != null )
281                 {
282                     mojoAnnotationContent.setSince( since.getValue() );
283                 }
284 
285                 DocletTag deprecated = findInClassHierarchy( javaClass, "deprecated" );
286                 if ( deprecated != null )
287                 {
288                     mojoAnnotationContent.setDeprecated( deprecated.getValue() );
289                 }
290             }
291 
292             Map<String, JavaField> fieldsMap = extractFieldParameterTags( javaClass, javaClassesMap );
293 
294             // populate parameters
295             Map<String, ParameterAnnotationContent> parameters =
296                 getParametersParentHierarchy( entry.getValue(), new HashMap<String, ParameterAnnotationContent>(),
297                                               mojoAnnotatedClasses );
298             for ( Map.Entry<String, ParameterAnnotationContent> parameter : new TreeMap<String, ParameterAnnotationContent>(
299                 parameters ).entrySet() )
300             {
301                 JavaField javaField = fieldsMap.get( parameter.getKey() );
302                 if ( javaField == null )
303                 {
304                     continue;
305                 }
306 
307                 ParameterAnnotationContent parameterAnnotationContent = parameter.getValue();
308                 parameterAnnotationContent.setDescription( javaField.getComment() );
309 
310                 DocletTag deprecated = javaField.getTagByName( "deprecated" );
311                 if ( deprecated != null )
312                 {
313                     parameterAnnotationContent.setDeprecated( deprecated.getValue() );
314                 }
315 
316                 DocletTag since = javaField.getTagByName( "since" );
317                 if ( since != null )
318                 {
319                     parameterAnnotationContent.setSince( since.getValue() );
320                 }
321             }
322 
323             // populate components
324             for ( Map.Entry<String, ComponentAnnotationContent> component : entry.getValue().getComponents().entrySet() )
325             {
326                 JavaField javaField = fieldsMap.get( component.getKey() );
327                 if ( javaField == null )
328                 {
329                     continue;
330                 }
331 
332                 ComponentAnnotationContent componentAnnotationContent = component.getValue();
333                 componentAnnotationContent.setDescription( javaField.getComment() );
334 
335                 DocletTag deprecated = javaField.getTagByName( "deprecated" );
336                 if ( deprecated != null )
337                 {
338                     componentAnnotationContent.setDeprecated( deprecated.getValue() );
339                 }
340 
341                 DocletTag since = javaField.getTagByName( "since" );
342                 if ( since != null )
343                 {
344                     componentAnnotationContent.setSince( since.getValue() );
345                 }
346             }
347 
348         }
349 
350     }
351 
352     /**
353      * @param javaClass not null
354      * @param tagName   not null
355      * @return docletTag instance
356      */
357     private DocletTag findInClassHierarchy( JavaClass javaClass, String tagName )
358     {
359         DocletTag tag = javaClass.getTagByName( tagName );
360 
361         if ( tag == null )
362         {
363             JavaClass superClass = javaClass.getSuperJavaClass();
364 
365             if ( superClass != null )
366             {
367                 tag = findInClassHierarchy( superClass, tagName );
368             }
369         }
370 
371         return tag;
372     }
373 
374     /**
375      * extract fields that are either parameters or components.
376      *
377      * @param javaClass not null
378      * @return map with Mojo parameters names as keys
379      */
380     private Map<String, JavaField> extractFieldParameterTags( JavaClass javaClass,
381                                                               Map<String, JavaClass> javaClassesMap )
382     {
383         Map<String, JavaField> rawParams = new TreeMap<String, com.thoughtworks.qdox.model.JavaField>();
384 
385         // we have to add the parent fields first, so that they will be overwritten by the local fields if
386         // that actually happens...
387         JavaClass superClass = javaClass.getSuperJavaClass();
388 
389         if ( superClass != null )
390         {
391             if ( superClass.getFields().length > 0 )
392             {
393                 rawParams = extractFieldParameterTags( superClass, javaClassesMap );
394             }
395             // maybe sources comes from scan of sources artifact
396             superClass = javaClassesMap.get( superClass.getFullyQualifiedName() );
397             if ( superClass != null )
398             {
399                 rawParams = extractFieldParameterTags( superClass, javaClassesMap );
400             }
401         }
402         else
403         {
404 
405             rawParams = new TreeMap<String, JavaField>();
406         }
407 
408         JavaField[] classFields = javaClass.getFields();
409 
410         if ( classFields != null )
411         {
412             for ( JavaField field : classFields )
413             {
414                 rawParams.put( field.getName(), field );
415             }
416         }
417         return rawParams;
418     }
419 
420     protected Map<String, JavaClass> discoverClasses( final PluginToolsRequest request )
421     {
422         return discoverClasses( request.getEncoding(), request.getProject() );
423     }
424 
425     @SuppressWarnings( "unchecked" )
426     protected Map<String, JavaClass> discoverClasses( final String encoding, final MavenProject project )
427     {
428         List<File> sources = new ArrayList<File>();
429 
430         for ( String source : (List<String>) project.getCompileSourceRoots() )
431         {
432             sources.add( new File( source ) );
433         }
434 
435         // TODO be more dynamic
436         File generatedPlugin = new File( project.getBasedir(), "target/generated-sources/plugin" );
437         if ( !project.getCompileSourceRoots().contains( generatedPlugin.getAbsolutePath() )
438             && generatedPlugin.exists() )
439         {
440             sources.add( generatedPlugin );
441         }
442 
443         return discoverClasses( encoding, sources );
444     }
445 
446     protected Map<String, JavaClass> discoverClasses( final String encoding, List<File> sourceDirectories )
447     {
448         JavaDocBuilder builder = new JavaDocBuilder();
449         builder.setEncoding( encoding );
450 
451         for ( File source : sourceDirectories )
452         {
453             builder.addSourceTree( source );
454         }
455 
456         JavaClass[] javaClasses = builder.getClasses();
457 
458         if ( javaClasses == null || javaClasses.length < 1 )
459         {
460             return Collections.emptyMap();
461         }
462 
463         Map<String, JavaClass> javaClassMap = new HashMap<String, JavaClass>( javaClasses.length );
464 
465         for ( JavaClass javaClass : javaClasses )
466         {
467             javaClassMap.put( javaClass.getFullyQualifiedName(), javaClass );
468         }
469 
470         return javaClassMap;
471     }
472 
473     private List<MojoDescriptor> toMojoDescriptors( Map<String, MojoAnnotatedClass> mojoAnnotatedClasses,
474                                                     PluginDescriptor pluginDescriptor )
475         throws DuplicateParameterException, InvalidParameterException
476     {
477         List<MojoDescriptor> mojoDescriptors = new ArrayList<MojoDescriptor>( mojoAnnotatedClasses.size() );
478         for ( MojoAnnotatedClass mojoAnnotatedClass : mojoAnnotatedClasses.values() )
479         {
480             // no mojo so skip it
481             if ( mojoAnnotatedClass.getMojo() == null )
482             {
483                 continue;
484             }
485 
486             ExtendedMojoDescriptor mojoDescriptor = new ExtendedMojoDescriptor();
487 
488             //mojoDescriptor.setRole( mojoAnnotatedClass.getClassName() );
489             //mojoDescriptor.setRoleHint( "default" );
490             mojoDescriptor.setImplementation( mojoAnnotatedClass.getClassName() );
491             mojoDescriptor.setLanguage( "java" );
492 
493             MojoAnnotationContent mojo = mojoAnnotatedClass.getMojo();
494 
495             mojoDescriptor.setDescription( mojo.getDescription() );
496             mojoDescriptor.setSince( mojo.getSince() );
497             mojo.setDeprecated( mojo.getDeprecated() );
498 
499             mojoDescriptor.setProjectRequired( mojo.requiresProject() );
500 
501             mojoDescriptor.setRequiresReports( mojo.requiresReports() );
502 
503             mojoDescriptor.setComponentConfigurator( mojo.configurator() );
504 
505             mojoDescriptor.setInheritedByDefault( mojo.inheritByDefault() );
506 
507             mojoDescriptor.setInstantiationStrategy( mojo.instantiationStrategy().id() );
508 
509             mojoDescriptor.setAggregator( mojo.aggregator() );
510             mojoDescriptor.setDependencyResolutionRequired( mojo.requiresDependencyResolution().id() );
511             mojoDescriptor.setDependencyCollectionRequired( mojo.requiresDependencyCollection().id() );
512 
513             mojoDescriptor.setDirectInvocationOnly( mojo.requiresDirectInvocation() );
514             mojoDescriptor.setDeprecated( mojo.getDeprecated() );
515             mojoDescriptor.setThreadSafe( mojo.threadSafe() );
516 
517             ExecuteAnnotationContent execute = findExecuteInParentHierarchy( mojoAnnotatedClass, mojoAnnotatedClasses );
518             if ( execute != null )
519             {
520                 mojoDescriptor.setExecuteGoal( execute.goal() );
521                 mojoDescriptor.setExecuteLifecycle( execute.lifecycle() );
522                 mojoDescriptor.setExecutePhase( execute.phase().id() );
523             }
524 
525             mojoDescriptor.setExecutionStrategy( mojo.executionStrategy() );
526             // ???
527             //mojoDescriptor.alwaysExecute(mojo.a)
528 
529             mojoDescriptor.setGoal( mojo.name() );
530             mojoDescriptor.setOnlineRequired( mojo.requiresOnline() );
531 
532             mojoDescriptor.setPhase( mojo.defaultPhase().id() );
533 
534             Map<String, ParameterAnnotationContent> parameters =
535                 getParametersParentHierarchy( mojoAnnotatedClass, new HashMap<String, ParameterAnnotationContent>(),
536                                               mojoAnnotatedClasses );
537 
538             for ( ParameterAnnotationContent parameterAnnotationContent : new TreeSet<ParameterAnnotationContent>(
539                 parameters.values() ) )
540             {
541                 org.apache.maven.plugin.descriptor.Parameter parameter =
542                     new org.apache.maven.plugin.descriptor.Parameter();
543                 parameter.setName( parameterAnnotationContent.getFieldName() );
544                 parameter.setAlias( parameterAnnotationContent.alias() );
545                 parameter.setDefaultValue( parameterAnnotationContent.defaultValue() );
546                 parameter.setDeprecated( parameterAnnotationContent.getDeprecated() );
547                 parameter.setDescription( parameterAnnotationContent.getDescription() );
548                 parameter.setEditable( !parameterAnnotationContent.readonly() );
549                 String property = parameterAnnotationContent.property();
550                 if ( StringUtils.contains( property, '$' ) || StringUtils.contains( property, '{' )
551                     || StringUtils.contains( property, '}' ) )
552                 {
553                     throw new InvalidParameterException(
554                         "Invalid property for parameter '" + parameter.getName() + "', " + "forbidden characters ${}: "
555                             + property, null );
556                 }
557                 parameter.setExpression( StringUtils.isEmpty( property ) ? "" : "${" + property + "}" );
558                 parameter.setType( parameterAnnotationContent.getClassName() );
559                 parameter.setSince( parameterAnnotationContent.getSince() );
560                 parameter.setRequired( parameterAnnotationContent.required() );
561 
562                 mojoDescriptor.addParameter( parameter );
563             }
564 
565             Map<String, ComponentAnnotationContent> components =
566                 getComponentsParentHierarchy( mojoAnnotatedClass, new HashMap<String, ComponentAnnotationContent>(),
567                                               mojoAnnotatedClasses );
568 
569             for ( ComponentAnnotationContent componentAnnotationContent : new TreeSet<ComponentAnnotationContent>(
570                 components.values() ) )
571             {
572                 org.apache.maven.plugin.descriptor.Parameter parameter =
573                     new org.apache.maven.plugin.descriptor.Parameter();
574                 parameter.setName( componentAnnotationContent.getFieldName() );
575 
576                 String expression = PluginUtils.MAVEN_COMPONENTS.get( componentAnnotationContent.getRoleClassName() );
577                 if ( expression == null )
578                 {
579                     parameter.setRequirement( new Requirement( componentAnnotationContent.getRoleClassName(),
580                                                                componentAnnotationContent.hint() ) );
581                 }
582                 else
583                 {
584                     parameter.setDefaultValue( expression );
585                     parameter.setImplementation( componentAnnotationContent.getRoleClassName() );
586                     parameter.setType( componentAnnotationContent.getRoleClassName() );
587                 }
588                 parameter.setDeprecated( componentAnnotationContent.getDeprecated() );
589                 parameter.setSince( componentAnnotationContent.getSince() );
590 
591                 // same behaviour as JavaMojoDescriptorExtractor
592                 //parameter.setRequired( ... );
593                 parameter.setEditable( false );
594                 mojoDescriptor.addParameter( parameter );
595             }
596 
597             mojoDescriptor.setPluginDescriptor( pluginDescriptor );
598 
599             mojoDescriptors.add( mojoDescriptor );
600         }
601         return mojoDescriptors;
602     }
603 
604     protected ExecuteAnnotationContent findExecuteInParentHierarchy( MojoAnnotatedClass mojoAnnotatedClass,
605                                                                      Map<String, MojoAnnotatedClass> mojoAnnotatedClasses )
606     {
607 
608         if ( mojoAnnotatedClass.getExecute() != null )
609         {
610             return mojoAnnotatedClass.getExecute();
611         }
612         String parentClassName = mojoAnnotatedClass.getParentClassName();
613         if ( StringUtils.isEmpty( parentClassName ) )
614         {
615             return null;
616         }
617         MojoAnnotatedClass parent = mojoAnnotatedClasses.get( parentClassName );
618         if ( parent == null )
619         {
620             return null;
621         }
622         return findExecuteInParentHierarchy( parent, mojoAnnotatedClasses );
623     }
624 
625 
626     protected Map<String, ParameterAnnotationContent> getParametersParentHierarchy(
627         MojoAnnotatedClass mojoAnnotatedClass, Map<String, ParameterAnnotationContent> parameters,
628         Map<String, MojoAnnotatedClass> mojoAnnotatedClasses )
629     {
630         List<ParameterAnnotationContent> parameterAnnotationContents = new ArrayList<ParameterAnnotationContent>();
631 
632         parameterAnnotationContents =
633             getParametersParent( mojoAnnotatedClass, parameterAnnotationContents, mojoAnnotatedClasses );
634 
635         // move to parent first to build the Map
636         Collections.reverse( parameterAnnotationContents );
637 
638         Map<String, ParameterAnnotationContent> map =
639             new HashMap<String, ParameterAnnotationContent>( parameterAnnotationContents.size() );
640 
641         for ( ParameterAnnotationContent parameterAnnotationContent : parameterAnnotationContents )
642         {
643             map.put( parameterAnnotationContent.getFieldName(), parameterAnnotationContent );
644         }
645         return map;
646     }
647 
648     protected List<ParameterAnnotationContent> getParametersParent( MojoAnnotatedClass mojoAnnotatedClass,
649                                                                     List<ParameterAnnotationContent> parameterAnnotationContents,
650                                                                     Map<String, MojoAnnotatedClass> mojoAnnotatedClasses )
651     {
652         parameterAnnotationContents.addAll( mojoAnnotatedClass.getParameters().values() );
653         String parentClassName = mojoAnnotatedClass.getParentClassName();
654         if ( parentClassName != null )
655         {
656             MojoAnnotatedClass parent = mojoAnnotatedClasses.get( parentClassName );
657             if ( parent != null )
658             {
659                 return getParametersParent( parent, parameterAnnotationContents, mojoAnnotatedClasses );
660             }
661         }
662         return parameterAnnotationContents;
663     }
664 
665     protected Map<String, ComponentAnnotationContent> getComponentsParentHierarchy(
666         MojoAnnotatedClass mojoAnnotatedClass, Map<String, ComponentAnnotationContent> components,
667         Map<String, MojoAnnotatedClass> mojoAnnotatedClasses )
668     {
669         List<ComponentAnnotationContent> componentAnnotationContents = new ArrayList<ComponentAnnotationContent>();
670 
671         componentAnnotationContents =
672             getComponentParent( mojoAnnotatedClass, componentAnnotationContents, mojoAnnotatedClasses );
673 
674         // move to parent first to build the Map
675         Collections.reverse( componentAnnotationContents );
676 
677         Map<String, ComponentAnnotationContent> map =
678             new HashMap<String, ComponentAnnotationContent>( componentAnnotationContents.size() );
679 
680         for ( ComponentAnnotationContent componentAnnotationContent : componentAnnotationContents )
681         {
682             map.put( componentAnnotationContent.getFieldName(), componentAnnotationContent );
683         }
684         return map;
685     }
686 
687     protected List<ComponentAnnotationContent> getComponentParent( MojoAnnotatedClass mojoAnnotatedClass,
688                                                                    List<ComponentAnnotationContent> componentAnnotationContents,
689                                                                    Map<String, MojoAnnotatedClass> mojoAnnotatedClasses )
690     {
691         componentAnnotationContents.addAll( mojoAnnotatedClass.getComponents().values() );
692         String parentClassName = mojoAnnotatedClass.getParentClassName();
693         if ( parentClassName != null )
694         {
695             MojoAnnotatedClass parent = mojoAnnotatedClasses.get( parentClassName );
696             if ( parent != null )
697             {
698                 return getComponentParent( parent, componentAnnotationContents, mojoAnnotatedClasses );
699             }
700         }
701         return componentAnnotationContents;
702     }
703 
704     protected MavenProject getFromProjectReferences( Artifact artifact, MavenProject project )
705     {
706         if ( project.getProjectReferences() == null || project.getProjectReferences().isEmpty() )
707         {
708             return null;
709         }
710         @SuppressWarnings( "unchecked" ) Collection<MavenProject> mavenProjects =
711             project.getProjectReferences().values();
712         for ( MavenProject mavenProject : mavenProjects )
713         {
714             if ( StringUtils.equals( mavenProject.getId(), artifact.getId() ) )
715             {
716                 return mavenProject;
717             }
718         }
719         return null;
720     }
721 
722 }