001 package org.apache.maven.tools.plugin.extractor.java; 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 022 import com.thoughtworks.qdox.JavaDocBuilder; 023 import com.thoughtworks.qdox.model.DocletTag; 024 import com.thoughtworks.qdox.model.JavaClass; 025 import com.thoughtworks.qdox.model.JavaField; 026 import com.thoughtworks.qdox.model.Type; 027 028 import org.apache.maven.plugin.descriptor.InvalidParameterException; 029 import org.apache.maven.plugin.descriptor.InvalidPluginDescriptorException; 030 import org.apache.maven.plugin.descriptor.MojoDescriptor; 031 import org.apache.maven.plugin.descriptor.Parameter; 032 import org.apache.maven.plugin.descriptor.PluginDescriptor; 033 import org.apache.maven.plugin.descriptor.Requirement; 034 import org.apache.maven.project.MavenProject; 035 import org.apache.maven.tools.plugin.DefaultPluginToolsRequest; 036 import org.apache.maven.tools.plugin.ExtendedMojoDescriptor; 037 import org.apache.maven.tools.plugin.PluginToolsRequest; 038 import org.apache.maven.tools.plugin.extractor.MojoDescriptorExtractor; 039 import org.apache.maven.tools.plugin.extractor.ExtractionException; 040 import org.apache.maven.tools.plugin.util.PluginUtils; 041 042 import org.codehaus.plexus.component.annotations.Component; 043 import org.codehaus.plexus.logging.AbstractLogEnabled; 044 import org.codehaus.plexus.util.StringUtils; 045 046 import java.io.File; 047 import java.util.ArrayList; 048 import java.util.List; 049 import java.util.Map; 050 import java.util.TreeMap; 051 052 /** 053 * Extracts Mojo descriptors from <a href="http://java.sun.com/">Java</a> sources. 054 * <br/> 055 * For more information about the usage tag, have a look to: 056 * <a href="http://maven.apache.org/developers/mojo-api-specification.html"> 057 * http://maven.apache.org/developers/mojo-api-specification.html</a> 058 * 059 * @todo need to add validation directives so that systems embedding maven2 can 060 * get validation directives to help users in IDEs. 061 * @version $Id: JavaMojoDescriptorExtractor.java 1353231 2012-06-24 08:36:58Z hboutemy $ 062 * @see org.apache.maven.plugin.descriptor.MojoDescriptor 063 */ 064 @Component( role = MojoDescriptorExtractor.class, hint = "java" ) 065 public class JavaMojoDescriptorExtractor 066 extends AbstractLogEnabled 067 implements MojoDescriptorExtractor, JavaMojoAnnotation 068 { 069 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#INSTANTIATION_STRATEGY} instead of. */ 070 public static final String MAVEN_PLUGIN_INSTANTIATION = JavaMojoAnnotation.INSTANTIATION_STRATEGY; 071 072 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#CONFIGURATOR} instead of. */ 073 public static final String CONFIGURATOR = JavaMojoAnnotation.CONFIGURATOR; 074 075 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#PARAMETER} instead of. */ 076 public static final String PARAMETER = JavaMojoAnnotation.PARAMETER; 077 078 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#PARAMETER_EXPRESSION} instead of. */ 079 public static final String PARAMETER_EXPRESSION = JavaMojoAnnotation.PARAMETER_EXPRESSION; 080 081 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#PARAMETER_DEFAULT_VALUE} instead of. */ 082 public static final String PARAMETER_DEFAULT_VALUE = JavaMojoAnnotation.PARAMETER_DEFAULT_VALUE; 083 084 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#PARAMETER_ALIAS} instead of. */ 085 public static final String PARAMETER_ALIAS = JavaMojoAnnotation.PARAMETER_ALIAS; 086 087 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#SINCE} instead of. */ 088 public static final String SINCE = JavaMojoAnnotation.SINCE; 089 090 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#PARAMETER_IMPLEMENTATION} instead of. */ 091 public static final String PARAMETER_IMPLEMENTATION = JavaMojoAnnotation.PARAMETER_IMPLEMENTATION; 092 093 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#REQUIRED} instead of. */ 094 public static final String REQUIRED = JavaMojoAnnotation.REQUIRED; 095 096 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#DEPRECATED} instead of. */ 097 public static final String DEPRECATED = JavaMojoAnnotation.DEPRECATED; 098 099 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#READONLY} instead of. */ 100 public static final String READONLY = JavaMojoAnnotation.READONLY; 101 102 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#GOAL} instead of. */ 103 public static final String GOAL = JavaMojoAnnotation.GOAL; 104 105 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#PHASE} instead of. */ 106 public static final String PHASE = JavaMojoAnnotation.PHASE; 107 108 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#EXECUTE} instead of. */ 109 public static final String EXECUTE = JavaMojoAnnotation.EXECUTE; 110 111 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#EXECUTE_LIFECYCLE} instead of. */ 112 public static final String EXECUTE_LIFECYCLE = JavaMojoAnnotation.EXECUTE_LIFECYCLE; 113 114 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#EXECUTE_PHASE} instead of. */ 115 public static final String EXECUTE_PHASE = JavaMojoAnnotation.EXECUTE_PHASE; 116 117 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#EXECUTE_GOAL} instead of. */ 118 public static final String EXECUTE_GOAL = JavaMojoAnnotation.EXECUTE_GOAL; 119 120 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#DESCRIPTION} instead of. */ 121 public static final String GOAL_DESCRIPTION = JavaMojoAnnotation.DESCRIPTION; 122 123 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#REQUIRES_DEPENDENCY_RESOLUTION} instead of. */ 124 public static final String GOAL_REQUIRES_DEPENDENCY_RESOLUTION = JavaMojoAnnotation.REQUIRES_DEPENDENCY_RESOLUTION; 125 126 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#REQUIRES_PROJECT} instead of. */ 127 public static final String GOAL_REQUIRES_PROJECT = JavaMojoAnnotation.REQUIRES_PROJECT; 128 129 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#REQUIRES_REPORTS} instead of. */ 130 public static final String GOAL_REQUIRES_REPORTS = JavaMojoAnnotation.REQUIRES_REPORTS; 131 132 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#AGGREGATOR} instead of. */ 133 public static final String GOAL_IS_AGGREGATOR = JavaMojoAnnotation.AGGREGATOR; 134 135 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#REQUIRES_ONLINE} instead of. */ 136 public static final String GOAL_REQUIRES_ONLINE = JavaMojoAnnotation.REQUIRES_ONLINE; 137 138 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#INHERIT_BY_DEFAULT} instead of. */ 139 public static final String GOAL_INHERIT_BY_DEFAULT = JavaMojoAnnotation.INHERIT_BY_DEFAULT; 140 141 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#MULTI_EXECUTION_STRATEGY} instead of. */ 142 public static final String GOAL_MULTI_EXECUTION_STRATEGY = JavaMojoAnnotation.MULTI_EXECUTION_STRATEGY; 143 144 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#REQUIRES_DIRECT_INVOCATION} instead of. */ 145 public static final String GOAL_REQUIRES_DIRECT_INVOCATION = JavaMojoAnnotation.REQUIRES_DIRECT_INVOCATION; 146 147 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#COMPONENT} instead of. */ 148 public static final String COMPONENT = JavaMojoAnnotation.COMPONENT; 149 150 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#COMPONENT_ROLE} instead of. */ 151 public static final String COMPONENT_ROLE = JavaMojoAnnotation.COMPONENT_ROLE; 152 153 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#COMPONENT_ROLEHINT} instead of. */ 154 public static final String COMPONENT_ROLEHINT = JavaMojoAnnotation.COMPONENT_ROLEHINT; 155 156 /** 157 * @param parameter not null 158 * @param i positive number 159 * @throws InvalidParameterException if any 160 */ 161 protected void validateParameter( Parameter parameter, int i ) 162 throws InvalidParameterException 163 { 164 // TODO: remove when backward compatibility is no longer an issue. 165 String name = parameter.getName(); 166 167 if ( name == null ) 168 { 169 throw new InvalidParameterException( "name", i ); 170 } 171 172 // TODO: remove when backward compatibility is no longer an issue. 173 String type = parameter.getType(); 174 175 if ( type == null ) 176 { 177 throw new InvalidParameterException( "type", i ); 178 } 179 180 // TODO: remove when backward compatibility is no longer an issue. 181 String description = parameter.getDescription(); 182 183 if ( description == null ) 184 { 185 throw new InvalidParameterException( "description", i ); 186 } 187 } 188 189 // ---------------------------------------------------------------------- 190 // Mojo descriptor creation from @tags 191 // ---------------------------------------------------------------------- 192 193 /** 194 * @param javaClass not null 195 * @return a mojo descriptor 196 * @throws InvalidPluginDescriptorException if any 197 */ 198 protected MojoDescriptor createMojoDescriptor( JavaClass javaClass ) 199 throws InvalidPluginDescriptorException 200 { 201 ExtendedMojoDescriptor mojoDescriptor = new ExtendedMojoDescriptor(); 202 mojoDescriptor.setLanguage( "java" ); 203 mojoDescriptor.setImplementation( javaClass.getFullyQualifiedName() ); 204 mojoDescriptor.setDescription( javaClass.getComment() ); 205 206 // ---------------------------------------------------------------------- 207 // Mojo annotations in alphabetical order 208 // ---------------------------------------------------------------------- 209 210 // Aggregator flag 211 DocletTag aggregator = findInClassHierarchy( javaClass, JavaMojoAnnotation.AGGREGATOR ); 212 if ( aggregator != null ) 213 { 214 mojoDescriptor.setAggregator( true ); 215 } 216 217 // Configurator hint 218 DocletTag configurator = findInClassHierarchy( javaClass, JavaMojoAnnotation.CONFIGURATOR ); 219 if ( configurator != null ) 220 { 221 mojoDescriptor.setComponentConfigurator( configurator.getValue() ); 222 } 223 224 // Additional phase to execute first 225 DocletTag execute = findInClassHierarchy( javaClass, JavaMojoAnnotation.EXECUTE ); 226 if ( execute != null ) 227 { 228 String executePhase = execute.getNamedParameter( JavaMojoAnnotation.EXECUTE_PHASE ); 229 String executeGoal = execute.getNamedParameter( JavaMojoAnnotation.EXECUTE_GOAL ); 230 231 if ( executePhase == null && executeGoal == null ) 232 { 233 throw new InvalidPluginDescriptorException( javaClass.getFullyQualifiedName() 234 + ": @execute tag requires either a 'phase' or 'goal' parameter" ); 235 } 236 else if ( executePhase != null && executeGoal != null ) 237 { 238 throw new InvalidPluginDescriptorException( javaClass.getFullyQualifiedName() 239 + ": @execute tag can have only one of a 'phase' or 'goal' parameter" ); 240 } 241 mojoDescriptor.setExecutePhase( executePhase ); 242 mojoDescriptor.setExecuteGoal( executeGoal ); 243 244 String lifecycle = execute.getNamedParameter( JavaMojoAnnotation.EXECUTE_LIFECYCLE ); 245 if ( lifecycle != null ) 246 { 247 mojoDescriptor.setExecuteLifecycle( lifecycle ); 248 if ( mojoDescriptor.getExecuteGoal() != null ) 249 { 250 throw new InvalidPluginDescriptorException( javaClass.getFullyQualifiedName() 251 + ": @execute lifecycle requires a phase instead of a goal" ); 252 } 253 } 254 } 255 256 // Goal name 257 DocletTag goal = findInClassHierarchy( javaClass, JavaMojoAnnotation.GOAL ); 258 if ( goal != null ) 259 { 260 mojoDescriptor.setGoal( goal.getValue() ); 261 } 262 263 // inheritByDefault flag 264 boolean value = 265 getBooleanTagValue( javaClass, JavaMojoAnnotation.INHERIT_BY_DEFAULT, 266 mojoDescriptor.isInheritedByDefault() ); 267 mojoDescriptor.setInheritedByDefault( value ); 268 269 // instantiationStrategy 270 DocletTag tag = findInClassHierarchy( javaClass, JavaMojoAnnotation.INSTANTIATION_STRATEGY ); 271 if ( tag != null ) 272 { 273 mojoDescriptor.setInstantiationStrategy( tag.getValue() ); 274 } 275 276 // executionStrategy (and deprecated @attainAlways) 277 tag = findInClassHierarchy( javaClass, JavaMojoAnnotation.MULTI_EXECUTION_STRATEGY ); 278 if ( tag != null ) 279 { 280 getLogger().warn( "@" + JavaMojoAnnotation.MULTI_EXECUTION_STRATEGY + " in " 281 + javaClass.getFullyQualifiedName() + " is deprecated: please use '@" 282 + JavaMojoAnnotation.EXECUTION_STATEGY + " always' instead." ); 283 mojoDescriptor.setExecutionStrategy( MojoDescriptor.MULTI_PASS_EXEC_STRATEGY ); 284 } 285 else 286 { 287 mojoDescriptor.setExecutionStrategy( MojoDescriptor.SINGLE_PASS_EXEC_STRATEGY ); 288 } 289 tag = findInClassHierarchy( javaClass, JavaMojoAnnotation.EXECUTION_STATEGY ); 290 if ( tag != null ) 291 { 292 mojoDescriptor.setExecutionStrategy( tag.getValue() ); 293 } 294 295 // Phase name 296 DocletTag phase = findInClassHierarchy( javaClass, JavaMojoAnnotation.PHASE ); 297 if ( phase != null ) 298 { 299 mojoDescriptor.setPhase( phase.getValue() ); 300 } 301 302 // Dependency resolution flag 303 DocletTag requiresDependencyResolution = 304 findInClassHierarchy( javaClass, JavaMojoAnnotation.REQUIRES_DEPENDENCY_RESOLUTION ); 305 if ( requiresDependencyResolution != null ) 306 { 307 String v = requiresDependencyResolution.getValue(); 308 309 if ( StringUtils.isEmpty( v ) ) 310 { 311 v = "runtime"; 312 } 313 314 mojoDescriptor.setDependencyResolutionRequired( v ); 315 } 316 317 // Dependency collection flag 318 DocletTag requiresDependencyCollection = 319 findInClassHierarchy( javaClass, JavaMojoAnnotation.REQUIRES_DEPENDENCY_COLLECTION ); 320 if ( requiresDependencyCollection != null ) 321 { 322 String v = requiresDependencyCollection.getValue(); 323 324 if ( StringUtils.isEmpty( v ) ) 325 { 326 v = "runtime"; 327 } 328 329 mojoDescriptor.setDependencyCollectionRequired( v ); 330 } 331 332 // requiresDirectInvocation flag 333 value = 334 getBooleanTagValue( javaClass, JavaMojoAnnotation.REQUIRES_DIRECT_INVOCATION, 335 mojoDescriptor.isDirectInvocationOnly() ); 336 mojoDescriptor.setDirectInvocationOnly( value ); 337 338 // Online flag 339 value = 340 getBooleanTagValue( javaClass, JavaMojoAnnotation.REQUIRES_ONLINE, mojoDescriptor.isOnlineRequired() ); 341 mojoDescriptor.setOnlineRequired( value ); 342 343 // Project flag 344 value = 345 getBooleanTagValue( javaClass, JavaMojoAnnotation.REQUIRES_PROJECT, mojoDescriptor.isProjectRequired() ); 346 mojoDescriptor.setProjectRequired( value ); 347 348 // requiresReports flag 349 value = 350 getBooleanTagValue( javaClass, JavaMojoAnnotation.REQUIRES_REPORTS, mojoDescriptor.isRequiresReports() ); 351 mojoDescriptor.setRequiresReports( value ); 352 353 // ---------------------------------------------------------------------- 354 // Javadoc annotations in alphabetical order 355 // ---------------------------------------------------------------------- 356 357 // Deprecation hint 358 DocletTag deprecated = javaClass.getTagByName( JavaMojoAnnotation.DEPRECATED ); 359 if ( deprecated != null ) 360 { 361 mojoDescriptor.setDeprecated( deprecated.getValue() ); 362 } 363 364 // What version it was introduced in 365 DocletTag since = findInClassHierarchy( javaClass, JavaMojoAnnotation.SINCE ); 366 if ( since != null ) 367 { 368 mojoDescriptor.setSince( since.getValue() ); 369 } 370 371 // Thread-safe mojo 372 373 value = getBooleanTagValue( javaClass, JavaMojoAnnotation.THREAD_SAFE, true, mojoDescriptor.isThreadSafe() ); 374 mojoDescriptor.setThreadSafe( value ); 375 376 extractParameters( mojoDescriptor, javaClass ); 377 378 return mojoDescriptor; 379 } 380 381 /** 382 * @param javaClass not null 383 * @param tagName not null 384 * @param defaultValue the wanted default value 385 * @return the boolean value of the given tagName 386 * @see #findInClassHierarchy(JavaClass, String) 387 */ 388 private static boolean getBooleanTagValue( JavaClass javaClass, String tagName, boolean defaultValue ) 389 { 390 DocletTag tag = findInClassHierarchy( javaClass, tagName ); 391 392 if ( tag != null ) 393 { 394 String value = tag.getValue(); 395 396 if ( StringUtils.isNotEmpty( value ) ) 397 { 398 defaultValue = Boolean.valueOf( value ).booleanValue(); 399 } 400 } 401 return defaultValue; 402 } 403 404 /** 405 * @param javaClass not null 406 * @param tagName not null 407 * @param defaultForTag The wanted default value when only the tagname is present 408 * @param defaultValue the wanted default value when the tag is not specified 409 * @return the boolean value of the given tagName 410 * @see #findInClassHierarchy(JavaClass, String) 411 */ 412 private static boolean getBooleanTagValue( JavaClass javaClass, String tagName, boolean defaultForTag, 413 boolean defaultValue ) 414 { 415 DocletTag tag = findInClassHierarchy( javaClass, tagName ); 416 417 if ( tag != null ) 418 { 419 String value = tag.getValue(); 420 421 if ( StringUtils.isNotEmpty( value ) ) 422 { 423 return Boolean.valueOf( value ).booleanValue(); 424 } 425 else 426 { 427 return defaultForTag; 428 } 429 } 430 return defaultValue; 431 } 432 433 /** 434 * @param javaClass not null 435 * @param tagName not null 436 * @return docletTag instance 437 */ 438 private static DocletTag findInClassHierarchy( JavaClass javaClass, String tagName ) 439 { 440 DocletTag tag = javaClass.getTagByName( tagName ); 441 442 if ( tag == null ) 443 { 444 JavaClass superClass = javaClass.getSuperJavaClass(); 445 446 if ( superClass != null ) 447 { 448 tag = findInClassHierarchy( superClass, tagName ); 449 } 450 } 451 452 return tag; 453 } 454 455 /** 456 * @param mojoDescriptor not null 457 * @param javaClass not null 458 * @throws InvalidPluginDescriptorException if any 459 */ 460 private void extractParameters( MojoDescriptor mojoDescriptor, JavaClass javaClass ) 461 throws InvalidPluginDescriptorException 462 { 463 // --------------------------------------------------------------------------------- 464 // We're resolving class-level, ancestor-class-field, local-class-field order here. 465 // --------------------------------------------------------------------------------- 466 467 Map<String, JavaField> rawParams = extractFieldParameterTags( javaClass ); 468 469 for ( Map.Entry<String, JavaField> entry : rawParams.entrySet() ) 470 { 471 JavaField field = entry.getValue(); 472 473 Type type = field.getType(); 474 475 Parameter pd = new Parameter(); 476 477 pd.setName( entry.getKey() ); 478 479 if ( !type.isArray() ) 480 { 481 pd.setType( type.getValue() ); 482 } 483 else 484 { 485 StringBuilder value = new StringBuilder( type.getValue() ); 486 487 int remaining = type.getDimensions(); 488 489 while ( remaining-- > 0 ) 490 { 491 value.append( "[]" ); 492 } 493 494 pd.setType( value.toString() ); 495 } 496 497 pd.setDescription( field.getComment() ); 498 499 DocletTag deprecationTag = field.getTagByName( JavaMojoAnnotation.DEPRECATED ); 500 501 if ( deprecationTag != null ) 502 { 503 pd.setDeprecated( deprecationTag.getValue() ); 504 } 505 506 DocletTag sinceTag = field.getTagByName( JavaMojoAnnotation.SINCE ); 507 if ( sinceTag != null ) 508 { 509 pd.setSince( sinceTag.getValue() ); 510 } 511 512 DocletTag componentTag = field.getTagByName( JavaMojoAnnotation.COMPONENT ); 513 514 if ( componentTag != null ) 515 { 516 // Component tag 517 String role = componentTag.getNamedParameter( JavaMojoAnnotation.COMPONENT_ROLE ); 518 519 if ( role == null ) 520 { 521 role = field.getType().toString(); 522 } 523 524 String roleHint = componentTag.getNamedParameter( JavaMojoAnnotation.COMPONENT_ROLEHINT ); 525 526 if ( roleHint == null ) 527 { 528 // support alternate syntax for better compatibility with the Plexus CDC. 529 roleHint = componentTag.getNamedParameter( "role-hint" ); 530 } 531 532 // recognize Maven-injected objects as components annotations instead of parameters 533 String expression = PluginUtils.MAVEN_COMPONENTS.get( role ); 534 535 if ( expression == null ) 536 { 537 // normal component 538 pd.setRequirement( new Requirement( role, roleHint ) ); 539 } 540 else 541 { 542 // not a component but a Maven object to be transformed into an expression/property 543 pd.setDefaultValue( expression ); 544 pd.setType( role ); 545 pd.setRequired( true ); 546 } 547 548 pd.setEditable( false ); 549 /* TODO: or better like this? Need @component fields be editable for the user? 550 pd.setEditable( field.getTagByName( READONLY ) == null ); 551 */ 552 } 553 else 554 { 555 // Parameter tag 556 DocletTag parameter = field.getTagByName( JavaMojoAnnotation.PARAMETER ); 557 558 pd.setRequired( field.getTagByName( JavaMojoAnnotation.REQUIRED ) != null ); 559 560 pd.setEditable( field.getTagByName( JavaMojoAnnotation.READONLY ) == null ); 561 562 String alias = parameter.getNamedParameter( JavaMojoAnnotation.PARAMETER_ALIAS ); 563 564 if ( !StringUtils.isEmpty( alias ) ) 565 { 566 pd.setAlias( alias ); 567 } 568 569 String expression = parameter.getNamedParameter( JavaMojoAnnotation.PARAMETER_EXPRESSION ); 570 String property = parameter.getNamedParameter( JavaMojoAnnotation.PARAMETER_PROPERTY ); 571 572 if ( StringUtils.isNotEmpty( expression ) && StringUtils.isNotEmpty( property ) ) 573 { 574 getLogger().error( javaClass.getFullyQualifiedName() + "#" + field.getName() + ":" ); 575 getLogger().error( " Cannot use both:" ); 576 getLogger().error( " @parameter expression=\"${property}\"" ); 577 getLogger().error( " and" ); 578 getLogger().error( " @parameter property=\"property\"" ); 579 getLogger().error( " Second syntax is preferred." ); 580 throw new InvalidParameterException( javaClass.getFullyQualifiedName() + "#" + field.getName() 581 + ": cannot" + " use both @parameter expression and property", null ); 582 } 583 584 if ( StringUtils.isNotEmpty( expression ) ) 585 { 586 getLogger().warn( javaClass.getFullyQualifiedName() + "#" + field.getName() + ":" ); 587 getLogger().warn( " The syntax" ); 588 getLogger().warn( " @parameter expression=\"${property}\"" ); 589 getLogger().warn( " is deprecated, please use" ); 590 getLogger().warn( " @parameter property=\"property\"" ); 591 getLogger().warn( " instead." ); 592 593 } 594 else if ( StringUtils.isNotEmpty( property ) ) 595 { 596 expression = "${" + property + "}"; 597 } 598 599 pd.setExpression( expression ); 600 601 if ( StringUtils.isNotEmpty( expression ) && expression.startsWith( "${component." ) ) 602 { 603 getLogger().warn( javaClass.getFullyQualifiedName() + "#" + field.getName() + ":" ); 604 getLogger().warn( " The syntax" ); 605 getLogger().warn( " @parameter expression=\"${component.<role>#<roleHint>}\"" ); 606 getLogger().warn( " is deprecated, please use" ); 607 getLogger().warn( " @component role=\"<role>\" roleHint=\"<roleHint>\"" ); 608 getLogger().warn( " instead." ); 609 } 610 611 if ( "${reports}".equals( pd.getExpression() ) ) 612 { 613 mojoDescriptor.setRequiresReports( true ); 614 } 615 616 pd.setDefaultValue( parameter.getNamedParameter( JavaMojoAnnotation.PARAMETER_DEFAULT_VALUE ) ); 617 618 pd.setImplementation( parameter.getNamedParameter( JavaMojoAnnotation.PARAMETER_IMPLEMENTATION ) ); 619 } 620 621 mojoDescriptor.addParameter( pd ); 622 } 623 } 624 625 /** 626 * extract fields that are either parameters or components. 627 * 628 * @param javaClass not null 629 * @return map with Mojo parameters names as keys 630 */ 631 private Map<String, JavaField> extractFieldParameterTags( JavaClass javaClass ) 632 { 633 Map<String, JavaField> rawParams; 634 635 // we have to add the parent fields first, so that they will be overwritten by the local fields if 636 // that actually happens... 637 JavaClass superClass = javaClass.getSuperJavaClass(); 638 639 if ( superClass != null ) 640 { 641 rawParams = extractFieldParameterTags( superClass ); 642 } 643 else 644 { 645 rawParams = new TreeMap<String, JavaField>(); 646 } 647 648 JavaField[] classFields = javaClass.getFields(); 649 650 if ( classFields != null ) 651 { 652 for ( JavaField field : classFields ) 653 { 654 if ( field.getTagByName( JavaMojoAnnotation.PARAMETER ) != null 655 || field.getTagByName( JavaMojoAnnotation.COMPONENT ) != null ) 656 { 657 rawParams.put( field.getName(), field ); 658 } 659 } 660 } 661 return rawParams; 662 } 663 664 /** {@inheritDoc} */ 665 public List<MojoDescriptor> execute( MavenProject project, PluginDescriptor pluginDescriptor ) 666 throws ExtractionException, InvalidPluginDescriptorException 667 { 668 return execute( new DefaultPluginToolsRequest( project, pluginDescriptor ) ); 669 } 670 671 /** {@inheritDoc} */ 672 public List<MojoDescriptor> execute( PluginToolsRequest request ) 673 throws ExtractionException, InvalidPluginDescriptorException 674 { 675 JavaClass[] javaClasses = discoverClasses( request ); 676 677 List<MojoDescriptor> descriptors = new ArrayList<MojoDescriptor>(); 678 679 for ( JavaClass javaClass : javaClasses ) 680 { 681 DocletTag tag = javaClass.getTagByName( GOAL ); 682 683 if ( tag != null ) 684 { 685 MojoDescriptor mojoDescriptor = createMojoDescriptor( javaClass ); 686 mojoDescriptor.setPluginDescriptor( request.getPluginDescriptor() ); 687 688 // Validate the descriptor as best we can before allowing it to be processed. 689 validate( mojoDescriptor ); 690 691 descriptors.add( mojoDescriptor ); 692 } 693 } 694 695 return descriptors; 696 } 697 698 /** 699 * @param request The plugin request. 700 * @return an array of java class 701 */ 702 @SuppressWarnings( "unchecked" ) 703 protected JavaClass[] discoverClasses( final PluginToolsRequest request ) 704 { 705 JavaDocBuilder builder = new JavaDocBuilder(); 706 builder.setEncoding( request.getEncoding() ); 707 708 MavenProject project = request.getProject(); 709 710 for ( String source : (List<String>) project.getCompileSourceRoots() ) 711 { 712 builder.addSourceTree( new File( source ) ); 713 } 714 715 // TODO be more dynamic 716 File generatedPlugin = new File( project.getBasedir(), "target/generated-sources/plugin" ); 717 if ( !project.getCompileSourceRoots().contains( generatedPlugin.getAbsolutePath() ) ) 718 { 719 builder.addSourceTree( generatedPlugin ); 720 } 721 722 return builder.getClasses(); 723 } 724 725 /** 726 * @param mojoDescriptor not null 727 * @throws InvalidParameterException if any 728 */ 729 protected void validate( MojoDescriptor mojoDescriptor ) 730 throws InvalidParameterException 731 { 732 @SuppressWarnings( "unchecked" ) 733 List<Parameter> parameters = mojoDescriptor.getParameters(); 734 735 if ( parameters != null ) 736 { 737 for ( int j = 0; j < parameters.size(); j++ ) 738 { 739 validateParameter( parameters.get( j ), j ); 740 } 741 } 742 } 743 }