001package org.apache.maven.tools.plugin.annotations; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import com.thoughtworks.qdox.JavaDocBuilder; 023import com.thoughtworks.qdox.model.DocletTag; 024import com.thoughtworks.qdox.model.JavaClass; 025import com.thoughtworks.qdox.model.JavaField; 026import org.apache.maven.artifact.Artifact; 027import org.apache.maven.artifact.factory.ArtifactFactory; 028import org.apache.maven.artifact.resolver.ArtifactNotFoundException; 029import org.apache.maven.artifact.resolver.ArtifactResolutionException; 030import org.apache.maven.artifact.resolver.ArtifactResolver; 031import org.apache.maven.plugin.descriptor.DuplicateParameterException; 032import org.apache.maven.plugin.descriptor.InvalidParameterException; 033import org.apache.maven.plugin.descriptor.InvalidPluginDescriptorException; 034import org.apache.maven.plugin.descriptor.MojoDescriptor; 035import org.apache.maven.plugin.descriptor.PluginDescriptor; 036import org.apache.maven.plugin.descriptor.Requirement; 037import org.apache.maven.project.MavenProject; 038import org.apache.maven.tools.plugin.ExtendedMojoDescriptor; 039import org.apache.maven.tools.plugin.PluginToolsRequest; 040import org.apache.maven.tools.plugin.annotations.datamodel.ComponentAnnotationContent; 041import org.apache.maven.tools.plugin.annotations.datamodel.ExecuteAnnotationContent; 042import org.apache.maven.tools.plugin.annotations.datamodel.MojoAnnotationContent; 043import org.apache.maven.tools.plugin.annotations.datamodel.ParameterAnnotationContent; 044import org.apache.maven.tools.plugin.annotations.scanner.MojoAnnotatedClass; 045import org.apache.maven.tools.plugin.annotations.scanner.MojoAnnotationsScanner; 046import org.apache.maven.tools.plugin.annotations.scanner.MojoAnnotationsScannerRequest; 047import org.apache.maven.tools.plugin.extractor.ExtractionException; 048import org.apache.maven.tools.plugin.extractor.MojoDescriptorExtractor; 049import org.apache.maven.tools.plugin.util.PluginUtils; 050import org.codehaus.plexus.archiver.UnArchiver; 051import org.codehaus.plexus.archiver.manager.ArchiverManager; 052import org.codehaus.plexus.archiver.manager.NoSuchArchiverException; 053import org.codehaus.plexus.component.annotations.Component; 054import org.codehaus.plexus.logging.AbstractLogEnabled; 055import org.codehaus.plexus.util.StringUtils; 056 057import java.io.File; 058import java.util.ArrayList; 059import java.util.Arrays; 060import java.util.Collection; 061import java.util.Collections; 062import java.util.HashMap; 063import java.util.HashSet; 064import java.util.List; 065import java.util.Map; 066import java.util.Set; 067import java.util.TreeMap; 068import java.util.TreeSet; 069 070/** 071 * JavaMojoDescriptorExtractor, a MojoDescriptor extractor to read descriptors from java classes with annotations. 072 * Notice that source files are also parsed to get description, since and deprecation information. 073 * 074 * @author Olivier Lamy 075 * @since 3.0 076 */ 077@Component( role = MojoDescriptorExtractor.class, hint = "java-annotations" ) 078public class JavaAnnotationsMojoDescriptorExtractor 079 extends AbstractLogEnabled 080 implements MojoDescriptorExtractor 081{ 082 083 @org.codehaus.plexus.component.annotations.Requirement 084 private MojoAnnotationsScanner mojoAnnotationsScanner; 085 086 @org.codehaus.plexus.component.annotations.Requirement 087 private ArtifactResolver artifactResolver; 088 089 @org.codehaus.plexus.component.annotations.Requirement 090 private ArtifactFactory artifactFactory; 091 092 @org.codehaus.plexus.component.annotations.Requirement 093 private ArchiverManager archiverManager; 094 095 public List<MojoDescriptor> execute( PluginToolsRequest request ) 096 throws ExtractionException, InvalidPluginDescriptorException 097 { 098 Map<String, MojoAnnotatedClass> mojoAnnotatedClasses = scanAnnotations( request ); 099 100 Map<String, JavaClass> javaClassesMap = scanJavadoc( request, mojoAnnotatedClasses.values() ); 101 102 populateDataFromJavadoc( mojoAnnotatedClasses, javaClassesMap ); 103 104 return toMojoDescriptors( mojoAnnotatedClasses, request.getPluginDescriptor() ); 105 } 106 107 private Map<String, MojoAnnotatedClass> scanAnnotations( PluginToolsRequest request ) 108 throws ExtractionException 109 { 110 MojoAnnotationsScannerRequest mojoAnnotationsScannerRequest = new MojoAnnotationsScannerRequest(); 111 112 File output = new File( request.getProject().getBuild().getOutputDirectory() ); 113 mojoAnnotationsScannerRequest.setClassesDirectories( Arrays.asList( output ) ); 114 115 mojoAnnotationsScannerRequest.setDependencies( request.getDependencies() ); 116 117 mojoAnnotationsScannerRequest.setProject( request.getProject() ); 118 119 return mojoAnnotationsScanner.scan( mojoAnnotationsScannerRequest ); 120 } 121 122 private Map<String, JavaClass> scanJavadoc( PluginToolsRequest request, 123 Collection<MojoAnnotatedClass> mojoAnnotatedClasses ) 124 throws ExtractionException 125 { 126 // found artifact from reactors to scan sources 127 // we currently only scan sources from reactors 128 List<MavenProject> mavenProjects = new ArrayList<MavenProject>(); 129 130 // if we need to scan sources from external artifacts 131 Set<Artifact> externalArtifacts = new HashSet<Artifact>(); 132 133 for ( MojoAnnotatedClass mojoAnnotatedClass : mojoAnnotatedClasses ) 134 { 135 if ( StringUtils.equals( mojoAnnotatedClass.getArtifact().getArtifactId(), 136 request.getProject().getArtifact().getArtifactId() ) ) 137 { 138 continue; 139 } 140 141 if ( !isMojoAnnnotatedClassCandidate( mojoAnnotatedClass ) ) 142 { 143 // we don't scan sources for classes without mojo annotations 144 continue; 145 } 146 147 MavenProject mavenProject = 148 getFromProjectReferences( mojoAnnotatedClass.getArtifact(), request.getProject() ); 149 150 if ( mavenProject != null ) 151 { 152 mavenProjects.add( mavenProject ); 153 } 154 else 155 { 156 externalArtifacts.add( mojoAnnotatedClass.getArtifact() ); 157 } 158 } 159 160 Map<String, JavaClass> javaClassesMap = new HashMap<String, JavaClass>(); 161 162 // try to get artifact with sources classifier, extract somewhere then scan for @since, @deprecated 163 for ( Artifact artifact : externalArtifacts ) 164 { 165 // parameter for test-sources too ?? olamy I need that for it test only 166 if ( StringUtils.equalsIgnoreCase( "tests", artifact.getClassifier() ) ) 167 { 168 javaClassesMap.putAll( discoverClassesFromSourcesJar( artifact, request, "test-sources" ) ); 169 } 170 else 171 { 172 javaClassesMap.putAll( discoverClassesFromSourcesJar( artifact, request, "sources" ) ); 173 } 174 175 } 176 177 for ( MavenProject mavenProject : mavenProjects ) 178 { 179 javaClassesMap.putAll( discoverClasses( request.getEncoding(), mavenProject ) ); 180 } 181 182 javaClassesMap.putAll( discoverClasses( request ) ); 183 184 return javaClassesMap; 185 } 186 187 private boolean isMojoAnnnotatedClassCandidate( MojoAnnotatedClass mojoAnnotatedClass ) 188 { 189 return mojoAnnotatedClass != null && mojoAnnotatedClass.hasAnnotations(); 190 } 191 192 protected Map<String, JavaClass> discoverClassesFromSourcesJar( Artifact artifact, PluginToolsRequest request, 193 String classifier ) 194 throws ExtractionException 195 { 196 try 197 { 198 Artifact sourcesArtifact = 199 artifactFactory.createArtifactWithClassifier( artifact.getGroupId(), artifact.getArtifactId(), 200 artifact.getVersion(), artifact.getType(), classifier ); 201 202 artifactResolver.resolve( sourcesArtifact, request.getRemoteRepos(), request.getLocal() ); 203 204 if ( sourcesArtifact.getFile() == null || !sourcesArtifact.getFile().exists() ) 205 { 206 // could not get artifact sources 207 return Collections.emptyMap(); 208 } 209 210 // extract sources to target/maven-plugin-plugin-sources/${groupId}/${artifact}/sources 211 File extractDirectory = new File( request.getProject().getBuild().getDirectory(), 212 "maven-plugin-plugin-sources/" + sourcesArtifact.getGroupId() + "/" 213 + sourcesArtifact.getArtifactId() + "/" + sourcesArtifact.getVersion() 214 + "/" + sourcesArtifact.getClassifier() ); 215 extractDirectory.mkdirs(); 216 217 UnArchiver unArchiver = archiverManager.getUnArchiver( "jar" ); 218 unArchiver.setSourceFile( sourcesArtifact.getFile() ); 219 unArchiver.setDestDirectory( extractDirectory ); 220 unArchiver.extract(); 221 222 return discoverClasses( request.getEncoding(), Arrays.asList( extractDirectory ) ); 223 } 224 catch ( ArtifactResolutionException e ) 225 { 226 throw new ExtractionException( e.getMessage(), e ); 227 } 228 catch ( ArtifactNotFoundException e ) 229 { 230 //throw new ExtractionException( e.getMessage(), e ); 231 getLogger().debug( "skip ArtifactNotFoundException:" + e.getMessage() ); 232 getLogger().warn( 233 "Unable to get sources artifact for " + artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" 234 + artifact.getVersion() + ". Some javadoc tags (@since, @deprecated and comments) won't be used" ); 235 return Collections.emptyMap(); 236 } 237 catch ( NoSuchArchiverException e ) 238 { 239 throw new ExtractionException( e.getMessage(), e ); 240 } 241 } 242 243 /** 244 * from sources scan to get @since and @deprecated and description of classes and fields. 245 * 246 * @param mojoAnnotatedClasses 247 * @param javaClassesMap 248 */ 249 protected void populateDataFromJavadoc( Map<String, MojoAnnotatedClass> mojoAnnotatedClasses, 250 Map<String, JavaClass> javaClassesMap ) 251 { 252 253 for ( Map.Entry<String, MojoAnnotatedClass> entry : mojoAnnotatedClasses.entrySet() ) 254 { 255 JavaClass javaClass = javaClassesMap.get( entry.getKey() ); 256 if ( javaClass == null ) 257 { 258 continue; 259 } 260 261 // populate class-level content 262 MojoAnnotationContent mojoAnnotationContent = entry.getValue().getMojo(); 263 if ( mojoAnnotationContent != null ) 264 { 265 mojoAnnotationContent.setDescription( javaClass.getComment() ); 266 267 DocletTag since = findInClassHierarchy( javaClass, "since" ); 268 if ( since != null ) 269 { 270 mojoAnnotationContent.setSince( since.getValue() ); 271 } 272 273 DocletTag deprecated = findInClassHierarchy( javaClass, "deprecated" ); 274 if ( deprecated != null ) 275 { 276 mojoAnnotationContent.setDeprecated( deprecated.getValue() ); 277 } 278 } 279 280 Map<String, JavaField> fieldsMap = extractFieldParameterTags( javaClass, javaClassesMap ); 281 282 // populate parameters 283 Map<String, ParameterAnnotationContent> parameters = 284 getParametersParentHierarchy( entry.getValue(), new HashMap<String, ParameterAnnotationContent>(), 285 mojoAnnotatedClasses ); 286 for ( Map.Entry<String, ParameterAnnotationContent> parameter : new TreeMap<String, ParameterAnnotationContent>( 287 parameters ).entrySet() ) 288 { 289 JavaField javaField = fieldsMap.get( parameter.getKey() ); 290 if ( javaField == null ) 291 { 292 continue; 293 } 294 295 ParameterAnnotationContent parameterAnnotationContent = parameter.getValue(); 296 parameterAnnotationContent.setDescription( javaField.getComment() ); 297 298 DocletTag deprecated = javaField.getTagByName( "deprecated" ); 299 if ( deprecated != null ) 300 { 301 parameterAnnotationContent.setDeprecated( deprecated.getValue() ); 302 } 303 304 DocletTag since = javaField.getTagByName( "since" ); 305 if ( since != null ) 306 { 307 parameterAnnotationContent.setSince( since.getValue() ); 308 } 309 } 310 311 // populate components 312 for ( Map.Entry<String, ComponentAnnotationContent> component : entry.getValue().getComponents().entrySet() ) 313 { 314 JavaField javaField = fieldsMap.get( component.getKey() ); 315 if ( javaField == null ) 316 { 317 continue; 318 } 319 320 ComponentAnnotationContent componentAnnotationContent = component.getValue(); 321 componentAnnotationContent.setDescription( javaField.getComment() ); 322 323 DocletTag deprecated = javaField.getTagByName( "deprecated" ); 324 if ( deprecated != null ) 325 { 326 componentAnnotationContent.setDeprecated( deprecated.getValue() ); 327 } 328 329 DocletTag since = javaField.getTagByName( "since" ); 330 if ( since != null ) 331 { 332 componentAnnotationContent.setSince( since.getValue() ); 333 } 334 } 335 336 } 337 338 } 339 340 /** 341 * @param javaClass not null 342 * @param tagName not null 343 * @return docletTag instance 344 */ 345 private DocletTag findInClassHierarchy( JavaClass javaClass, String tagName ) 346 { 347 DocletTag tag = javaClass.getTagByName( tagName ); 348 349 if ( tag == null ) 350 { 351 JavaClass superClass = javaClass.getSuperJavaClass(); 352 353 if ( superClass != null ) 354 { 355 tag = findInClassHierarchy( superClass, tagName ); 356 } 357 } 358 359 return tag; 360 } 361 362 /** 363 * extract fields that are either parameters or components. 364 * 365 * @param javaClass not null 366 * @return map with Mojo parameters names as keys 367 */ 368 private Map<String, JavaField> extractFieldParameterTags( JavaClass javaClass, 369 Map<String, JavaClass> javaClassesMap ) 370 { 371 Map<String, JavaField> rawParams = new TreeMap<String, com.thoughtworks.qdox.model.JavaField>(); 372 373 // we have to add the parent fields first, so that they will be overwritten by the local fields if 374 // that actually happens... 375 JavaClass superClass = javaClass.getSuperJavaClass(); 376 377 if ( superClass != null ) 378 { 379 if ( superClass.getFields().length > 0 ) 380 { 381 rawParams = extractFieldParameterTags( superClass, javaClassesMap ); 382 } 383 // maybe sources comes from scan of sources artifact 384 superClass = javaClassesMap.get( superClass.getFullyQualifiedName() ); 385 if ( superClass != null ) 386 { 387 rawParams = extractFieldParameterTags( superClass, javaClassesMap ); 388 } 389 } 390 else 391 { 392 393 rawParams = new TreeMap<String, JavaField>(); 394 } 395 396 JavaField[] classFields = javaClass.getFields(); 397 398 if ( classFields != null ) 399 { 400 for ( JavaField field : classFields ) 401 { 402 rawParams.put( field.getName(), field ); 403 } 404 } 405 return rawParams; 406 } 407 408 protected Map<String, JavaClass> discoverClasses( final PluginToolsRequest request ) 409 { 410 return discoverClasses( request.getEncoding(), request.getProject() ); 411 } 412 413 @SuppressWarnings( "unchecked" ) 414 protected Map<String, JavaClass> discoverClasses( final String encoding, final MavenProject project ) 415 { 416 List<File> sources = new ArrayList<File>(); 417 418 for ( String source : (List<String>) project.getCompileSourceRoots() ) 419 { 420 sources.add( new File( source ) ); 421 } 422 423 // TODO be more dynamic 424 File generatedPlugin = new File( project.getBasedir(), "target/generated-sources/plugin" ); 425 if ( !project.getCompileSourceRoots().contains( generatedPlugin.getAbsolutePath() ) 426 && generatedPlugin.exists() ) 427 { 428 sources.add( generatedPlugin ); 429 } 430 431 return discoverClasses( encoding, sources ); 432 } 433 434 protected Map<String, JavaClass> discoverClasses( final String encoding, List<File> sourceDirectories ) 435 { 436 JavaDocBuilder builder = new JavaDocBuilder(); 437 builder.setEncoding( encoding ); 438 439 for ( File source : sourceDirectories ) 440 { 441 builder.addSourceTree( source ); 442 } 443 444 JavaClass[] javaClasses = builder.getClasses(); 445 446 if ( javaClasses == null || javaClasses.length < 1 ) 447 { 448 return Collections.emptyMap(); 449 } 450 451 Map<String, JavaClass> javaClassMap = new HashMap<String, JavaClass>( javaClasses.length ); 452 453 for ( JavaClass javaClass : javaClasses ) 454 { 455 javaClassMap.put( javaClass.getFullyQualifiedName(), javaClass ); 456 } 457 458 return javaClassMap; 459 } 460 461 private List<MojoDescriptor> toMojoDescriptors( Map<String, MojoAnnotatedClass> mojoAnnotatedClasses, 462 PluginDescriptor pluginDescriptor ) 463 throws DuplicateParameterException, InvalidParameterException 464 { 465 List<MojoDescriptor> mojoDescriptors = new ArrayList<MojoDescriptor>( mojoAnnotatedClasses.size() ); 466 for ( MojoAnnotatedClass mojoAnnotatedClass : mojoAnnotatedClasses.values() ) 467 { 468 // no mojo so skip it 469 if ( mojoAnnotatedClass.getMojo() == null ) 470 { 471 continue; 472 } 473 474 ExtendedMojoDescriptor mojoDescriptor = new ExtendedMojoDescriptor(); 475 476 //mojoDescriptor.setRole( mojoAnnotatedClass.getClassName() ); 477 //mojoDescriptor.setRoleHint( "default" ); 478 mojoDescriptor.setImplementation( mojoAnnotatedClass.getClassName() ); 479 mojoDescriptor.setLanguage( "java" ); 480 481 MojoAnnotationContent mojo = mojoAnnotatedClass.getMojo(); 482 483 mojoDescriptor.setDescription( mojo.getDescription() ); 484 mojoDescriptor.setSince( mojo.getSince() ); 485 mojo.setDeprecated( mojo.getDeprecated() ); 486 487 mojoDescriptor.setProjectRequired( mojo.requiresProject() ); 488 489 mojoDescriptor.setRequiresReports( mojo.requiresReports() ); 490 491 mojoDescriptor.setComponentConfigurator( mojo.configurator() ); 492 493 mojoDescriptor.setInheritedByDefault( mojo.inheritByDefault() ); 494 495 mojoDescriptor.setInstantiationStrategy( mojo.instantiationStrategy().id() ); 496 497 mojoDescriptor.setAggregator( mojo.aggregator() ); 498 mojoDescriptor.setDependencyResolutionRequired( mojo.requiresDependencyResolution().id() ); 499 mojoDescriptor.setDependencyCollectionRequired( mojo.requiresDependencyCollection().id() ); 500 501 mojoDescriptor.setDirectInvocationOnly( mojo.requiresDirectInvocation() ); 502 mojoDescriptor.setDeprecated( mojo.getDeprecated() ); 503 mojoDescriptor.setThreadSafe( mojo.threadSafe() ); 504 505 ExecuteAnnotationContent execute = findExecuteInParentHierarchy( mojoAnnotatedClass, mojoAnnotatedClasses ); 506 if ( execute != null ) 507 { 508 mojoDescriptor.setExecuteGoal( execute.goal() ); 509 mojoDescriptor.setExecuteLifecycle( execute.lifecycle() ); 510 if ( execute.phase() != null ) 511 { 512 mojoDescriptor.setExecutePhase( execute.phase().id() ); 513 } 514 } 515 516 mojoDescriptor.setExecutionStrategy( mojo.executionStrategy() ); 517 // ??? 518 //mojoDescriptor.alwaysExecute(mojo.a) 519 520 mojoDescriptor.setGoal( mojo.name() ); 521 mojoDescriptor.setOnlineRequired( mojo.requiresOnline() ); 522 523 mojoDescriptor.setPhase( mojo.defaultPhase().id() ); 524 525 // Parameter annotations 526 Map<String, ParameterAnnotationContent> parameters = 527 getParametersParentHierarchy( mojoAnnotatedClass, new HashMap<String, ParameterAnnotationContent>(), 528 mojoAnnotatedClasses ); 529 530 for ( ParameterAnnotationContent parameterAnnotationContent : new TreeSet<ParameterAnnotationContent>( 531 parameters.values() ) ) 532 { 533 org.apache.maven.plugin.descriptor.Parameter parameter = 534 new org.apache.maven.plugin.descriptor.Parameter(); 535 String name = 536 StringUtils.isEmpty( parameterAnnotationContent.name() ) ? parameterAnnotationContent.getFieldName() 537 : parameterAnnotationContent.name(); 538 parameter.setName( name ); 539 parameter.setAlias( parameterAnnotationContent.alias() ); 540 parameter.setDefaultValue( parameterAnnotationContent.defaultValue() ); 541 parameter.setDeprecated( parameterAnnotationContent.getDeprecated() ); 542 parameter.setDescription( parameterAnnotationContent.getDescription() ); 543 parameter.setEditable( !parameterAnnotationContent.readonly() ); 544 String property = parameterAnnotationContent.property(); 545 if ( StringUtils.contains( property, '$' ) || StringUtils.contains( property, '{' ) 546 || StringUtils.contains( property, '}' ) ) 547 { 548 throw new InvalidParameterException( 549 "Invalid property for parameter '" + parameter.getName() + "', " + "forbidden characters ${}: " 550 + property, null ); 551 } 552 parameter.setExpression( StringUtils.isEmpty( property ) ? "" : "${" + property + "}" ); 553 parameter.setType( parameterAnnotationContent.getClassName() ); 554 parameter.setSince( parameterAnnotationContent.getSince() ); 555 parameter.setRequired( parameterAnnotationContent.required() ); 556 557 mojoDescriptor.addParameter( parameter ); 558 } 559 560 // Component annotations 561 Map<String, ComponentAnnotationContent> components = 562 getComponentsParentHierarchy( mojoAnnotatedClass, new HashMap<String, ComponentAnnotationContent>(), 563 mojoAnnotatedClasses ); 564 565 for ( ComponentAnnotationContent componentAnnotationContent : new TreeSet<ComponentAnnotationContent>( 566 components.values() ) ) 567 { 568 org.apache.maven.plugin.descriptor.Parameter parameter = 569 new org.apache.maven.plugin.descriptor.Parameter(); 570 parameter.setName( componentAnnotationContent.getFieldName() ); 571 572 // recognize Maven-injected objects as components annotations instead of parameters 573 String expression = PluginUtils.MAVEN_COMPONENTS.get( componentAnnotationContent.getRoleClassName() ); 574 if ( expression == null ) 575 { 576 // normal component 577 parameter.setRequirement( new Requirement( componentAnnotationContent.getRoleClassName(), 578 componentAnnotationContent.hint() ) ); 579 } 580 else 581 { 582 // not a component but a Maven object to be transformed into an expression/property: deprecated 583 getLogger().warn( "Deprecated @component for " + parameter.getName() + " field in " 584 + mojoAnnotatedClass.getClassName() + "." 585 + ": replace with @parameter name=\"" + expression + "\" @readonly" ); 586 parameter.setDefaultValue( expression ); 587 parameter.setType( componentAnnotationContent.getRoleClassName() ); 588 parameter.setRequired( true ); 589 } 590 parameter.setDeprecated( componentAnnotationContent.getDeprecated() ); 591 parameter.setSince( componentAnnotationContent.getSince() ); 592 593 // same behaviour as JavaMojoDescriptorExtractor 594 //parameter.setRequired( ... ); 595 parameter.setEditable( false ); 596 597 mojoDescriptor.addParameter( parameter ); 598 } 599 600 mojoDescriptor.setPluginDescriptor( pluginDescriptor ); 601 602 mojoDescriptors.add( mojoDescriptor ); 603 } 604 return mojoDescriptors; 605 } 606 607 protected ExecuteAnnotationContent findExecuteInParentHierarchy( MojoAnnotatedClass mojoAnnotatedClass, 608 Map<String, MojoAnnotatedClass> mojoAnnotatedClasses ) 609 { 610 if ( mojoAnnotatedClass.getExecute() != null ) 611 { 612 return mojoAnnotatedClass.getExecute(); 613 } 614 String parentClassName = mojoAnnotatedClass.getParentClassName(); 615 if ( StringUtils.isEmpty( parentClassName ) ) 616 { 617 return null; 618 } 619 MojoAnnotatedClass parent = mojoAnnotatedClasses.get( parentClassName ); 620 if ( parent == null ) 621 { 622 return null; 623 } 624 return findExecuteInParentHierarchy( parent, mojoAnnotatedClasses ); 625 } 626 627 628 protected Map<String, ParameterAnnotationContent> getParametersParentHierarchy( 629 MojoAnnotatedClass mojoAnnotatedClass, Map<String, ParameterAnnotationContent> parameters, 630 Map<String, MojoAnnotatedClass> mojoAnnotatedClasses ) 631 { 632 List<ParameterAnnotationContent> parameterAnnotationContents = new ArrayList<ParameterAnnotationContent>(); 633 634 parameterAnnotationContents = 635 getParametersParent( mojoAnnotatedClass, parameterAnnotationContents, mojoAnnotatedClasses ); 636 637 // move to parent first to build the Map 638 Collections.reverse( parameterAnnotationContents ); 639 640 Map<String, ParameterAnnotationContent> map = 641 new HashMap<String, ParameterAnnotationContent>( parameterAnnotationContents.size() ); 642 643 for ( ParameterAnnotationContent parameterAnnotationContent : parameterAnnotationContents ) 644 { 645 map.put( parameterAnnotationContent.getFieldName(), parameterAnnotationContent ); 646 } 647 return map; 648 } 649 650 protected List<ParameterAnnotationContent> getParametersParent( MojoAnnotatedClass mojoAnnotatedClass, 651 List<ParameterAnnotationContent> parameterAnnotationContents, 652 Map<String, MojoAnnotatedClass> mojoAnnotatedClasses ) 653 { 654 parameterAnnotationContents.addAll( mojoAnnotatedClass.getParameters().values() ); 655 String parentClassName = mojoAnnotatedClass.getParentClassName(); 656 if ( parentClassName != null ) 657 { 658 MojoAnnotatedClass parent = mojoAnnotatedClasses.get( parentClassName ); 659 if ( parent != null ) 660 { 661 return getParametersParent( parent, parameterAnnotationContents, mojoAnnotatedClasses ); 662 } 663 } 664 return parameterAnnotationContents; 665 } 666 667 protected Map<String, ComponentAnnotationContent> getComponentsParentHierarchy( 668 MojoAnnotatedClass mojoAnnotatedClass, Map<String, ComponentAnnotationContent> components, 669 Map<String, MojoAnnotatedClass> mojoAnnotatedClasses ) 670 { 671 List<ComponentAnnotationContent> componentAnnotationContents = new ArrayList<ComponentAnnotationContent>(); 672 673 componentAnnotationContents = 674 getComponentParent( mojoAnnotatedClass, componentAnnotationContents, mojoAnnotatedClasses ); 675 676 // move to parent first to build the Map 677 Collections.reverse( componentAnnotationContents ); 678 679 Map<String, ComponentAnnotationContent> map = 680 new HashMap<String, ComponentAnnotationContent>( componentAnnotationContents.size() ); 681 682 for ( ComponentAnnotationContent componentAnnotationContent : componentAnnotationContents ) 683 { 684 map.put( componentAnnotationContent.getFieldName(), componentAnnotationContent ); 685 } 686 return map; 687 } 688 689 protected List<ComponentAnnotationContent> getComponentParent( MojoAnnotatedClass mojoAnnotatedClass, 690 List<ComponentAnnotationContent> componentAnnotationContents, 691 Map<String, MojoAnnotatedClass> mojoAnnotatedClasses ) 692 { 693 componentAnnotationContents.addAll( mojoAnnotatedClass.getComponents().values() ); 694 String parentClassName = mojoAnnotatedClass.getParentClassName(); 695 if ( parentClassName != null ) 696 { 697 MojoAnnotatedClass parent = mojoAnnotatedClasses.get( parentClassName ); 698 if ( parent != null ) 699 { 700 return getComponentParent( parent, componentAnnotationContents, mojoAnnotatedClasses ); 701 } 702 } 703 return componentAnnotationContents; 704 } 705 706 protected MavenProject getFromProjectReferences( Artifact artifact, MavenProject project ) 707 { 708 if ( project.getProjectReferences() == null || project.getProjectReferences().isEmpty() ) 709 { 710 return null; 711 } 712 @SuppressWarnings( "unchecked" ) Collection<MavenProject> mavenProjects = 713 project.getProjectReferences().values(); 714 for ( MavenProject mavenProject : mavenProjects ) 715 { 716 if ( StringUtils.equals( mavenProject.getId(), artifact.getId() ) ) 717 { 718 return mavenProject; 719 } 720 } 721 return null; 722 } 723 724}