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     private boolean v4Api = false;
143 
144     /**
145      * Default constructor.
146      */
147     public MojoDescriptor()
148     {
149         this.parameters = new ArrayList<>();
150         setInstantiationStrategy( DEFAULT_INSTANTIATION_STRATEGY );
151         setComponentFactory( DEFAULT_LANGUAGE );
152     }
153 
154     // ----------------------------------------------------------------------
155     //
156     // ----------------------------------------------------------------------
157 
158     /**
159      * @return the language of this Mojo, i.e. <code>java</code>
160      */
161     public String getLanguage()
162     {
163         return getComponentFactory();
164     }
165 
166     /**
167      * @param language the new language
168      */
169     public void setLanguage( String language )
170     {
171         setComponentFactory( language );
172     }
173 
174     /**
175      * @return Description with reason of a Mojo deprecation.
176      */
177     public String getDeprecated()
178     {
179         return deprecated;
180     }
181 
182     /**
183      * @param deprecated Description with reason of a Mojo deprecation.
184      */
185     public void setDeprecated( String deprecated )
186     {
187         this.deprecated = deprecated;
188     }
189 
190     /**
191      * @return the list of parameters copy. Any change to returned list is NOT reflected on this instance. To add
192      * parameters, use {@link #addParameter(Parameter)} method.
193      */
194     public List<Parameter> getParameters()
195     {
196         return new ArrayList<>( parameters  );
197     }
198 
199     /**
200      * @param parameters the new list of parameters
201      * @throws DuplicateParameterException if any
202      */
203     public void setParameters( List<Parameter> parameters )
204         throws DuplicateParameterException
205     {
206         this.parameters.clear();
207         for ( Parameter parameter : parameters )
208         {
209             addParameter( parameter );
210         }
211     }
212 
213     /**
214      * @param parameter add a new parameter
215      * @throws DuplicateParameterException if any
216      */
217     public void addParameter( Parameter parameter )
218         throws DuplicateParameterException
219     {
220         if ( parameters.contains( parameter ) )
221         {
222             throw new DuplicateParameterException( parameter.getName()
223                 + " has been declared multiple times in mojo with goal: " + getGoal() + " (implementation: "
224                 + getImplementation() + ")" );
225         }
226 
227         parameters.add( parameter );
228     }
229 
230     /**
231      * @return the list parameters as a Map (keyed by {@link Parameter#getName()}) that is built from
232      * {@link #parameters} list on each call. In other words, the map returned is built on fly and is a copy.
233      * Any change to this map is NOT reflected on list and other way around!
234      */
235     public Map<String, Parameter> getParameterMap()
236     {
237         LinkedHashMap<String, Parameter> parameterMap = new LinkedHashMap<>();
238 
239         for ( Parameter pd : parameters )
240         {
241             parameterMap.put( pd.getName(), pd );
242         }
243 
244         return parameterMap;
245     }
246 
247     // ----------------------------------------------------------------------
248     // Dependency requirement
249     // ----------------------------------------------------------------------
250 
251     /**
252      * @param requiresDependencyResolution the new required dependencies in a specified scope
253      */
254     public void setDependencyResolutionRequired( String requiresDependencyResolution )
255     {
256         this.dependencyResolutionRequired = requiresDependencyResolution;
257     }
258 
259     public String getDependencyResolutionRequired()
260     {
261         return dependencyResolutionRequired;
262     }
263 
264     /**
265      * @return the required dependencies in a specified scope
266      * TODO the name is not intelligible
267      */
268     @Deprecated
269     public String isDependencyResolutionRequired()
270     {
271         return dependencyResolutionRequired;
272     }
273 
274     /**
275      * @since 3.0-alpha-3
276      */
277     public void setDependencyCollectionRequired( String requiresDependencyCollection )
278     {
279         this.dependencyCollectionRequired = requiresDependencyCollection;
280     }
281 
282     /**
283      * Gets the scope of (transitive) dependencies that should be collected. Dependency collection refers to the process
284      * of calculating the complete dependency tree in terms of artifact coordinates. In contrast to dependency
285      * resolution, this does not include the download of the files for the dependency artifacts. It is meant for mojos
286      * that only want to analyze the set of transitive dependencies, in particular during early lifecycle phases where
287      * full dependency resolution might fail due to projects which haven't been built yet.
288      *
289      * @return The scope of (transitive) dependencies that should be collected or {@code null} if none.
290      * @since 3.0-alpha-3
291      */
292     public String getDependencyCollectionRequired()
293     {
294         return dependencyCollectionRequired;
295     }
296 
297     // ----------------------------------------------------------------------
298     // Project requirement
299     // ----------------------------------------------------------------------
300 
301     /**
302      * @param requiresProject <code>true</code> if the Mojo needs a Maven project to be executed, <code>false</code>
303      * otherwise.
304      */
305     public void setProjectRequired( boolean requiresProject )
306     {
307         this.projectRequired = requiresProject;
308     }
309 
310     /**
311      * @return <code>true</code> if the Mojo needs a Maven project to be executed, <code>false</code> otherwise.
312      */
313     public boolean isProjectRequired()
314     {
315         return projectRequired;
316     }
317 
318     // ----------------------------------------------------------------------
319     // Online vs. Offline requirement
320     // ----------------------------------------------------------------------
321 
322     /**
323      * @param requiresOnline <code>true</code> if the Mojo is online, <code>false</code> otherwise.
324      */
325     public void setOnlineRequired( boolean requiresOnline )
326     {
327         this.onlineRequired = requiresOnline;
328     }
329 
330     /**
331      * @return <code>true</code> if the Mojo is online, <code>false</code> otherwise.
332      */
333     // blech! this isn't even intelligible as a method name. provided for
334     // consistency...
335     public boolean isOnlineRequired()
336     {
337         return onlineRequired;
338     }
339 
340     /**
341      * @return <code>true</code> if the Mojo is online, <code>false</code> otherwise.
342      */
343     // more english-friendly method...keep the code clean! :)
344     public boolean requiresOnline()
345     {
346         return onlineRequired;
347     }
348 
349     /**
350      * @return the bound phase name of the Mojo
351      */
352     public String getPhase()
353     {
354         return phase;
355     }
356 
357     /**
358      * @param phase the new bound phase name of the Mojo
359      */
360     public void setPhase( String phase )
361     {
362         this.phase = phase;
363     }
364 
365     /**
366      * @return the version when the Mojo was added to the API
367      */
368     public String getSince()
369     {
370         return since;
371     }
372 
373     /**
374      * @param since the new version when the Mojo was added to the API
375      */
376     public void setSince( String since )
377     {
378         this.since = since;
379     }
380 
381     /**
382      * @return The goal name of the Mojo
383      */
384     public String getGoal()
385     {
386         return goal;
387     }
388 
389     /**
390      * @param goal The new goal name of the Mojo
391      */
392     public void setGoal( String goal )
393     {
394         this.goal = goal;
395     }
396 
397     /**
398      * @return the invocation phase of the Mojo
399      */
400     public String getExecutePhase()
401     {
402         return executePhase;
403     }
404 
405     /**
406      * @param executePhase the new invocation phase of the Mojo
407      */
408     public void setExecutePhase( String executePhase )
409     {
410         this.executePhase = executePhase;
411     }
412 
413     /**
414      * @return <code>true</code> if the Mojo uses <code>always</code> for the <code>executionStrategy</code>
415      */
416     public boolean alwaysExecute()
417     {
418         return MULTI_PASS_EXEC_STRATEGY.equals( executionStrategy );
419     }
420 
421     /**
422      * @return the execution strategy
423      */
424     public String getExecutionStrategy()
425     {
426         return executionStrategy;
427     }
428 
429     /**
430      * @param executionStrategy the new execution strategy
431      */
432     public void setExecutionStrategy( String executionStrategy )
433     {
434         this.executionStrategy = executionStrategy;
435     }
436 
437     /**
438      * @return the mojo configuration
439      */
440     public PlexusConfiguration getMojoConfiguration()
441     {
442         if ( mojoConfiguration == null )
443         {
444             mojoConfiguration = new XmlPlexusConfiguration( "configuration" );
445         }
446         return mojoConfiguration;
447     }
448 
449     /**
450      * @param mojoConfiguration a new mojo configuration
451      */
452     public void setMojoConfiguration( PlexusConfiguration mojoConfiguration )
453     {
454         this.mojoConfiguration = mojoConfiguration;
455     }
456 
457     /** {@inheritDoc} */
458     public String getRole()
459     {
460         return isV4Api() ? "org.apache.maven.api.plugin.Mojo" : Mojo.ROLE;
461     }
462 
463     /** {@inheritDoc} */
464     public String getRoleHint()
465     {
466         return getId();
467     }
468 
469     /**
470      * @return the id of the mojo, based on the goal name
471      */
472     public String getId()
473     {
474         return getPluginDescriptor().getId() + ":" + getGoal();
475     }
476 
477     /**
478      * @return the full goal name
479      * @see PluginDescriptor#getGoalPrefix()
480      * @see #getGoal()
481      */
482     public String getFullGoalName()
483     {
484         return getPluginDescriptor().getGoalPrefix() + ":" + getGoal();
485     }
486 
487     /** {@inheritDoc} */
488     public String getComponentType()
489     {
490         return MAVEN_PLUGIN;
491     }
492 
493     /**
494      * @return the plugin descriptor
495      */
496     public PluginDescriptor getPluginDescriptor()
497     {
498         return pluginDescriptor;
499     }
500 
501     /**
502      * @param pluginDescriptor the new plugin descriptor
503      */
504     public void setPluginDescriptor( PluginDescriptor pluginDescriptor )
505     {
506         this.pluginDescriptor = pluginDescriptor;
507     }
508 
509     /**
510      * @return <code>true</code> if the Mojo is inherited, <code>false</code> otherwise.
511      */
512     public boolean isInheritedByDefault()
513     {
514         return inheritedByDefault;
515     }
516 
517     /**
518      * @param inheritedByDefault <code>true</code> if the Mojo is inherited, <code>false</code> otherwise.
519      */
520     public void setInheritedByDefault( boolean inheritedByDefault )
521     {
522         this.inheritedByDefault = inheritedByDefault;
523     }
524 
525     /** {@inheritDoc} */
526     public boolean equals( Object object )
527     {
528         if ( this == object )
529         {
530             return true;
531         }
532 
533         if ( object instanceof MojoDescriptor )
534         {
535             MojoDescriptor other = (MojoDescriptor) object;
536 
537             return Objects.equals( getPluginDescriptor(), other.getPluginDescriptor() )
538                     && Objects.equals( getGoal(), other.getGoal() );
539         }
540 
541         return false;
542     }
543 
544     /** {@inheritDoc} */
545     public int hashCode()
546     {
547         return Objects.hash( getGoal(), getPluginDescriptor() );
548     }
549 
550     /**
551      * @return the invocation lifecycle of the Mojo
552      */
553     public String getExecuteLifecycle()
554     {
555         return executeLifecycle;
556     }
557 
558     /**
559      * @param executeLifecycle the new invocation lifecycle of the Mojo
560      */
561     public void setExecuteLifecycle( String executeLifecycle )
562     {
563         this.executeLifecycle = executeLifecycle;
564     }
565 
566     /**
567      * @param aggregator <code>true</code> if the Mojo uses the Maven project and its child modules,
568      * <code>false</code> otherwise.
569      */
570     public void setAggregator( boolean aggregator )
571     {
572         this.aggregator = aggregator;
573     }
574 
575     /**
576      * @return <code>true</code> if the Mojo uses the Maven project and its child modules,
577      * <code>false</code> otherwise.
578      */
579     public boolean isAggregator()
580     {
581         return aggregator;
582     }
583 
584     /**
585      * @return <code>true</code> if the Mojo cannot be invoked directly, <code>false</code> otherwise.
586      */
587     public boolean isDirectInvocationOnly()
588     {
589         return directInvocationOnly;
590     }
591 
592     /**
593      * @param directInvocationOnly <code>true</code> if the Mojo cannot be invoked directly,
594      * <code>false</code> otherwise.
595      */
596     public void setDirectInvocationOnly( boolean directInvocationOnly )
597     {
598         this.directInvocationOnly = directInvocationOnly;
599     }
600 
601     /**
602      * @return <code>true</code> if the Mojo needs reports to run, <code>false</code> otherwise.
603      */
604     public boolean isRequiresReports()
605     {
606         return requiresReports;
607     }
608 
609     /**
610      * @param requiresReports <code>true</code> if the Mojo needs reports to run, <code>false</code> otherwise.
611      */
612     public void setRequiresReports( boolean requiresReports )
613     {
614         this.requiresReports = requiresReports;
615     }
616 
617     /**
618      * @param executeGoal the new invocation goal of the Mojo
619      */
620     public void setExecuteGoal( String executeGoal )
621     {
622         this.executeGoal = executeGoal;
623     }
624 
625     /**
626      * @return the invocation goal of the Mojo
627      */
628     public String getExecuteGoal()
629     {
630         return executeGoal;
631     }
632 
633 
634     /**
635      * @return True if the <code>Mojo</code> is thread-safe and can be run safely in parallel
636      * @since 3.0-beta-2
637      */
638     public boolean isThreadSafe()
639     {
640         return threadSafe;
641     }
642 
643     /**
644      * @param threadSafe indicates that the mojo is thread-safe and can be run safely in parallel
645      * @since 3.0-beta-2
646      */
647     public void setThreadSafe( boolean threadSafe )
648     {
649         this.threadSafe = threadSafe;
650     }
651 
652     /**
653      * @return {@code true} if this mojo forks either a goal or the lifecycle, {@code false} otherwise.
654      */
655     public boolean isForking()
656     {
657         return ( getExecuteGoal() != null && getExecuteGoal().length() > 0 )
658             || ( getExecutePhase() != null && getExecutePhase().length() > 0 );
659     }
660 
661     public boolean isV4Api()
662     {
663         return v4Api;
664     }
665 
666     public void setV4Api( boolean v4Api )
667     {
668         this.v4Api = v4Api;
669     }
670 
671     /**
672      * Creates a shallow copy of this mojo descriptor.
673      */
674     @Override
675     public MojoDescriptor clone()
676     {
677         try
678         {
679             return (MojoDescriptor) super.clone();
680         }
681         catch ( CloneNotSupportedException e )
682         {
683             throw new UnsupportedOperationException( e );
684         }
685     }
686 
687 }