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