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