View Javadoc
1   package org.apache.maven.plugin.descriptor;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.ArrayList;
23  import java.util.LinkedHashMap;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.Objects;
27  
28  import org.apache.maven.plugin.Mojo;
29  import org.codehaus.plexus.component.repository.ComponentDescriptor;
30  import org.codehaus.plexus.configuration.PlexusConfiguration;
31  import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
32  
33  /**
34   * The bean containing the Mojo descriptor.<br>
35   * For more information about the usage tag, have a look to:
36   * <a href="https://maven.apache.org/developers/mojo-api-specification.html">
37   * https://maven.apache.org/developers/mojo-api-specification.html</a>
38   *
39   * TODO is there a need for the delegation of MavenMojoDescriptor to this?
40   * Why not just extend ComponentDescriptor here?
41   */
42  public class MojoDescriptor
43      extends ComponentDescriptor<Mojo>
44      implements Cloneable
45  {
46      /** The Plexus component type */
47      public static final String MAVEN_PLUGIN = "maven-plugin";
48  
49      /** "once-per-session" execution strategy */
50      public static final String SINGLE_PASS_EXEC_STRATEGY = "once-per-session";
51  
52      /** "always" execution strategy */
53      public static final String MULTI_PASS_EXEC_STRATEGY = "always";
54  
55      private static final String DEFAULT_INSTANTIATION_STRATEGY = "per-lookup";
56  
57      private static final String DEFAULT_LANGUAGE = "java";
58  
59      private final ArrayList<Parameter> parameters;
60  
61      /** By default, the execution strategy is "once-per-session" */
62      private String executionStrategy = SINGLE_PASS_EXEC_STRATEGY;
63  
64      /**
65       * The goal name for the Mojo, that users will reference from the command line to execute the Mojo directly, or
66       * inside a POM in order to provide Mojo-specific configuration.
67       */
68      private String goal;
69  
70      /**
71       * Defines a default phase to bind a mojo execution to if the user does not explicitly set a phase in the POM.
72       * <i>Note:</i> This will not automagically make a mojo run when the plugin declaration is added to the POM. It
73       * merely enables the user to omit the <code>&lt;phase&gt;</code> element from the surrounding
74       * <code>&lt;execution&gt;</code> element.
75       */
76      private String phase;
77  
78      /** Specify the version when the Mojo was added to the API. Similar to Javadoc since. */
79      private String since;
80  
81      /** Reference the invocation phase of the Mojo. */
82      private String executePhase;
83  
84      /** Reference the invocation goal of the Mojo. */
85      private String executeGoal;
86  
87      /** Reference the invocation lifecycle of the Mojo. */
88      private String executeLifecycle;
89  
90      /**
91       * Description with reason of Mojo deprecation. Similar to Javadoc {@code @deprecated}.
92       * This will trigger a warning when a user tries to use a Mojo marked as deprecated.
93       */
94      private String deprecated;
95  
96      /**
97       * Flags this Mojo to run it in a multi-module way, i.e. aggregate the build with the set of projects listed as
98       * modules. By default, no need to aggregate the Maven project and its child modules
99       */
100     private boolean aggregator = false;
101 
102     // ----------------------------------------------------------------------
103     //
104     // ----------------------------------------------------------------------
105 
106     /** Specify the required dependencies in a specified scope */
107     private String dependencyResolutionRequired = null;
108 
109     /**
110      * The scope of (transitive) dependencies that should be collected but not resolved.
111      * @since 3.0-alpha-3
112      */
113     private String dependencyCollectionRequired;
114 
115     /**  By default, the Mojo needs a Maven project to be executed */
116     private boolean projectRequired = true;
117 
118     /**  By default, the Mojo is assumed to work offline as well */
119     private boolean onlineRequired = false;
120 
121     /**  Plugin configuration */
122     private PlexusConfiguration mojoConfiguration;
123 
124     /**  Plugin descriptor */
125     private PluginDescriptor pluginDescriptor;
126 
127     /**  By default, the Mojo is inherited */
128     private boolean inheritedByDefault = true;
129 
130     /**  By default, the Mojo cannot be invoked directly */
131     private boolean directInvocationOnly = false;
132 
133     /**  By default, the Mojo don't need reports to run */
134     private boolean requiresReports = false;
135 
136     /**
137      * By default, mojos are not threadsafe
138      * @since 3.0-beta-2
139      */
140     private boolean threadSafe = false;
141 
142     /**
143      * Default constructor.
144      */
145     public MojoDescriptor()
146     {
147         this.parameters = new ArrayList<>();
148         setInstantiationStrategy( DEFAULT_INSTANTIATION_STRATEGY );
149         setComponentFactory( DEFAULT_LANGUAGE );
150     }
151 
152     // ----------------------------------------------------------------------
153     //
154     // ----------------------------------------------------------------------
155 
156     /**
157      * @return the language of this Mojo, i.e. <code>java</code>
158      */
159     public String getLanguage()
160     {
161         return getComponentFactory();
162     }
163 
164     /**
165      * @param language the new language
166      */
167     public void setLanguage( String language )
168     {
169         setComponentFactory( language );
170     }
171 
172     /**
173      * @return Description with reason of a Mojo deprecation.
174      */
175     public String getDeprecated()
176     {
177         return deprecated;
178     }
179 
180     /**
181      * @param deprecated Description with reason of a Mojo deprecation.
182      */
183     public void setDeprecated( String deprecated )
184     {
185         this.deprecated = deprecated;
186     }
187 
188     /**
189      * @return the list of parameters copy. Any change to returned list is NOT reflected on this instance. To add
190      * parameters, use {@link #addParameter(Parameter)} method.
191      */
192     public List<Parameter> getParameters()
193     {
194         return new ArrayList<>( parameters  );
195     }
196 
197     /**
198      * @param parameters the new list of parameters
199      * @throws DuplicateParameterException if any
200      */
201     public void setParameters( List<Parameter> parameters )
202         throws DuplicateParameterException
203     {
204         this.parameters.clear();
205         for ( Parameter parameter : parameters )
206         {
207             addParameter( parameter );
208         }
209     }
210 
211     /**
212      * @param parameter add a new parameter
213      * @throws DuplicateParameterException if any
214      */
215     public void addParameter( Parameter parameter )
216         throws DuplicateParameterException
217     {
218         if ( parameters.contains( parameter ) )
219         {
220             throw new DuplicateParameterException( parameter.getName()
221                 + " has been declared multiple times in mojo with goal: " + getGoal() + " (implementation: "
222                 + getImplementation() + ")" );
223         }
224 
225         parameters.add( parameter );
226     }
227 
228     /**
229      * @return the list parameters as a Map (keyed by {@link Parameter#getName()}) that is built from
230      * {@link #parameters} list on each call. In other words, the map returned is built on fly and is a copy.
231      * Any change to this map is NOT reflected on list and other way around!
232      */
233     public Map<String, Parameter> getParameterMap()
234     {
235         LinkedHashMap<String, Parameter> parameterMap = new LinkedHashMap<>();
236 
237         for ( Parameter pd : parameters )
238         {
239             parameterMap.put( pd.getName(), pd );
240         }
241 
242         return parameterMap;
243     }
244 
245     // ----------------------------------------------------------------------
246     // Dependency requirement
247     // ----------------------------------------------------------------------
248 
249     /**
250      * @param requiresDependencyResolution the new required dependencies in a specified scope
251      */
252     public void setDependencyResolutionRequired( String requiresDependencyResolution )
253     {
254         this.dependencyResolutionRequired = requiresDependencyResolution;
255     }
256 
257     public String getDependencyResolutionRequired()
258     {
259         return dependencyResolutionRequired;
260     }
261 
262     /**
263      * @return the required dependencies in a specified scope
264      * TODO the name is not intelligible
265      */
266     @Deprecated
267     public String isDependencyResolutionRequired()
268     {
269         return dependencyResolutionRequired;
270     }
271 
272     /**
273      * @since 3.0-alpha-3
274      */
275     public void setDependencyCollectionRequired( String requiresDependencyCollection )
276     {
277         this.dependencyCollectionRequired = requiresDependencyCollection;
278     }
279 
280     /**
281      * Gets the scope of (transitive) dependencies that should be collected. Dependency collection refers to the process
282      * of calculating the complete dependency tree in terms of artifact coordinates. In contrast to dependency
283      * resolution, this does not include the download of the files for the dependency artifacts. It is meant for mojos
284      * that only want to analyze the set of transitive dependencies, in particular during early lifecycle phases where
285      * full dependency resolution might fail due to projects which haven't been built yet.
286      *
287      * @return The scope of (transitive) dependencies that should be collected or {@code null} if none.
288      * @since 3.0-alpha-3
289      */
290     public String getDependencyCollectionRequired()
291     {
292         return dependencyCollectionRequired;
293     }
294 
295     // ----------------------------------------------------------------------
296     // Project requirement
297     // ----------------------------------------------------------------------
298 
299     /**
300      * @param requiresProject <code>true</code> if the Mojo needs a Maven project to be executed, <code>false</code>
301      * otherwise.
302      */
303     public void setProjectRequired( boolean requiresProject )
304     {
305         this.projectRequired = requiresProject;
306     }
307 
308     /**
309      * @return <code>true</code> if the Mojo needs a Maven project to be executed, <code>false</code> otherwise.
310      */
311     public boolean isProjectRequired()
312     {
313         return projectRequired;
314     }
315 
316     // ----------------------------------------------------------------------
317     // Online vs. Offline requirement
318     // ----------------------------------------------------------------------
319 
320     /**
321      * @param requiresOnline <code>true</code> if the Mojo is online, <code>false</code> otherwise.
322      */
323     public void setOnlineRequired( boolean requiresOnline )
324     {
325         this.onlineRequired = requiresOnline;
326     }
327 
328     /**
329      * @return <code>true</code> if the Mojo is online, <code>false</code> otherwise.
330      */
331     // blech! this isn't even intelligible as a method name. provided for
332     // consistency...
333     public boolean isOnlineRequired()
334     {
335         return onlineRequired;
336     }
337 
338     /**
339      * @return <code>true</code> if the Mojo is online, <code>false</code> otherwise.
340      */
341     // more english-friendly method...keep the code clean! :)
342     public boolean requiresOnline()
343     {
344         return onlineRequired;
345     }
346 
347     /**
348      * @return the bound phase name of the Mojo
349      */
350     public String getPhase()
351     {
352         return phase;
353     }
354 
355     /**
356      * @param phase the new bound phase name of the Mojo
357      */
358     public void setPhase( String phase )
359     {
360         this.phase = phase;
361     }
362 
363     /**
364      * @return the version when the Mojo was added to the API
365      */
366     public String getSince()
367     {
368         return since;
369     }
370 
371     /**
372      * @param since the new version when the Mojo was added to the API
373      */
374     public void setSince( String since )
375     {
376         this.since = since;
377     }
378 
379     /**
380      * @return The goal name of the Mojo
381      */
382     public String getGoal()
383     {
384         return goal;
385     }
386 
387     /**
388      * @param goal The new goal name of the Mojo
389      */
390     public void setGoal( String goal )
391     {
392         this.goal = goal;
393     }
394 
395     /**
396      * @return the invocation phase of the Mojo
397      */
398     public String getExecutePhase()
399     {
400         return executePhase;
401     }
402 
403     /**
404      * @param executePhase the new invocation phase of the Mojo
405      */
406     public void setExecutePhase( String executePhase )
407     {
408         this.executePhase = executePhase;
409     }
410 
411     /**
412      * @return <code>true</code> if the Mojo uses <code>always</code> for the <code>executionStrategy</code>
413      */
414     public boolean alwaysExecute()
415     {
416         return MULTI_PASS_EXEC_STRATEGY.equals( executionStrategy );
417     }
418 
419     /**
420      * @return the execution strategy
421      */
422     public String getExecutionStrategy()
423     {
424         return executionStrategy;
425     }
426 
427     /**
428      * @param executionStrategy the new execution strategy
429      */
430     public void setExecutionStrategy( String executionStrategy )
431     {
432         this.executionStrategy = executionStrategy;
433     }
434 
435     /**
436      * @return the mojo configuration
437      */
438     public PlexusConfiguration getMojoConfiguration()
439     {
440         if ( mojoConfiguration == null )
441         {
442             mojoConfiguration = new XmlPlexusConfiguration( "configuration" );
443         }
444         return mojoConfiguration;
445     }
446 
447     /**
448      * @param mojoConfiguration a new mojo configuration
449      */
450     public void setMojoConfiguration( PlexusConfiguration mojoConfiguration )
451     {
452         this.mojoConfiguration = mojoConfiguration;
453     }
454 
455     /** {@inheritDoc} */
456     public String getRole()
457     {
458         return Mojo.ROLE;
459     }
460 
461     /** {@inheritDoc} */
462     public String getRoleHint()
463     {
464         return getId();
465     }
466 
467     /**
468      * @return the id of the mojo, based on the goal name
469      */
470     public String getId()
471     {
472         return getPluginDescriptor().getId() + ":" + getGoal();
473     }
474 
475     /**
476      * @return the full goal name
477      * @see PluginDescriptor#getGoalPrefix()
478      * @see #getGoal()
479      */
480     public String getFullGoalName()
481     {
482         return getPluginDescriptor().getGoalPrefix() + ":" + getGoal();
483     }
484 
485     /** {@inheritDoc} */
486     public String getComponentType()
487     {
488         return MAVEN_PLUGIN;
489     }
490 
491     /**
492      * @return the plugin descriptor
493      */
494     public PluginDescriptor getPluginDescriptor()
495     {
496         return pluginDescriptor;
497     }
498 
499     /**
500      * @param pluginDescriptor the new plugin descriptor
501      */
502     public void setPluginDescriptor( PluginDescriptor pluginDescriptor )
503     {
504         this.pluginDescriptor = pluginDescriptor;
505     }
506 
507     /**
508      * @return <code>true</code> if the Mojo is inherited, <code>false</code> otherwise.
509      */
510     public boolean isInheritedByDefault()
511     {
512         return inheritedByDefault;
513     }
514 
515     /**
516      * @param inheritedByDefault <code>true</code> if the Mojo is inherited, <code>false</code> otherwise.
517      */
518     public void setInheritedByDefault( boolean inheritedByDefault )
519     {
520         this.inheritedByDefault = inheritedByDefault;
521     }
522 
523     /** {@inheritDoc} */
524     public boolean equals( Object object )
525     {
526         if ( this == object )
527         {
528             return true;
529         }
530 
531         if ( object instanceof MojoDescriptor )
532         {
533             MojoDescriptor other = (MojoDescriptor) object;
534 
535             return Objects.equals( getPluginDescriptor(), other.getPluginDescriptor() )
536                     && Objects.equals( getGoal(), other.getGoal() );
537         }
538 
539         return false;
540     }
541 
542     /** {@inheritDoc} */
543     public int hashCode()
544     {
545         return Objects.hash( getGoal(), getPluginDescriptor() );
546     }
547 
548     /**
549      * @return the invocation lifecycle of the Mojo
550      */
551     public String getExecuteLifecycle()
552     {
553         return executeLifecycle;
554     }
555 
556     /**
557      * @param executeLifecycle the new invocation lifecycle of the Mojo
558      */
559     public void setExecuteLifecycle( String executeLifecycle )
560     {
561         this.executeLifecycle = executeLifecycle;
562     }
563 
564     /**
565      * @param aggregator <code>true</code> if the Mojo uses the Maven project and its child modules,
566      * <code>false</code> otherwise.
567      */
568     public void setAggregator( boolean aggregator )
569     {
570         this.aggregator = aggregator;
571     }
572 
573     /**
574      * @return <code>true</code> if the Mojo uses the Maven project and its child modules,
575      * <code>false</code> otherwise.
576      */
577     public boolean isAggregator()
578     {
579         return aggregator;
580     }
581 
582     /**
583      * @return <code>true</code> if the Mojo cannot be invoked directly, <code>false</code> otherwise.
584      */
585     public boolean isDirectInvocationOnly()
586     {
587         return directInvocationOnly;
588     }
589 
590     /**
591      * @param directInvocationOnly <code>true</code> if the Mojo cannot be invoked directly,
592      * <code>false</code> otherwise.
593      */
594     public void setDirectInvocationOnly( boolean directInvocationOnly )
595     {
596         this.directInvocationOnly = directInvocationOnly;
597     }
598 
599     /**
600      * @return <code>true</code> if the Mojo needs reports to run, <code>false</code> otherwise.
601      */
602     public boolean isRequiresReports()
603     {
604         return requiresReports;
605     }
606 
607     /**
608      * @param requiresReports <code>true</code> if the Mojo needs reports to run, <code>false</code> otherwise.
609      */
610     public void setRequiresReports( boolean requiresReports )
611     {
612         this.requiresReports = requiresReports;
613     }
614 
615     /**
616      * @param executeGoal the new invocation goal of the Mojo
617      */
618     public void setExecuteGoal( String executeGoal )
619     {
620         this.executeGoal = executeGoal;
621     }
622 
623     /**
624      * @return the invocation goal of the Mojo
625      */
626     public String getExecuteGoal()
627     {
628         return executeGoal;
629     }
630 
631 
632     /**
633      * @return True if the <code>Mojo</code> is thread-safe and can be run safely in parallel
634      * @since 3.0-beta-2
635      */
636     public boolean isThreadSafe()
637     {
638         return threadSafe;
639     }
640 
641     /**
642      * @param threadSafe indicates that the mojo is thread-safe and can be run safely in parallel
643      * @since 3.0-beta-2
644      */
645     public void setThreadSafe( boolean threadSafe )
646     {
647         this.threadSafe = threadSafe;
648     }
649 
650     /**
651      * @return {@code true} if this mojo forks either a goal or the lifecycle, {@code false} otherwise.
652      */
653     public boolean isForking()
654     {
655         return ( getExecuteGoal() != null && getExecuteGoal().length() > 0 )
656             || ( getExecutePhase() != null && getExecutePhase().length() > 0 );
657     }
658 
659     /**
660      * Creates a shallow copy of this mojo descriptor.
661      */
662     @Override
663     public MojoDescriptor clone()
664     {
665         try
666         {
667             return (MojoDescriptor) super.clone();
668         }
669         catch ( CloneNotSupportedException e )
670         {
671             throw new UnsupportedOperationException( e );
672         }
673     }
674 
675 }