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