001    package org.apache.maven.plugin.descriptor;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one
005     * or more contributor license agreements.  See the NOTICE file
006     * distributed with this work for additional information
007     * regarding copyright ownership.  The ASF licenses this file
008     * to you under the Apache License, Version 2.0 (the
009     * "License"); you may not use this file except in compliance
010     * with the License.  You may obtain a copy of the License at
011     *
012     *  http://www.apache.org/licenses/LICENSE-2.0
013     *
014     * Unless required by applicable law or agreed to in writing,
015     * software distributed under the License is distributed on an
016     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017     * KIND, either express or implied.  See the License for the
018     * specific language governing permissions and limitations
019     * under the License.
020     */
021    
022    import java.util.HashMap;
023    import java.util.LinkedList;
024    import java.util.List;
025    import java.util.Map;
026    
027    import org.apache.maven.plugin.Mojo;
028    import org.codehaus.plexus.component.repository.ComponentDescriptor;
029    import org.codehaus.plexus.configuration.PlexusConfiguration;
030    import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
031    
032    /**
033     * The bean containing the Mojo descriptor.
034     * <br/>
035     * For more information about the usage tag, have a look to:
036     * <a href="http://maven.apache.org/developers/mojo-api-specification.html">
037     * http://maven.apache.org/developers/mojo-api-specification.html</a>
038     *
039     * @todo is there a need for the delegation of MavenMojoDescriptor to this?
040     * Why not just extend ComponentDescriptor here?
041     */
042    public class MojoDescriptor
043        extends ComponentDescriptor<Mojo>
044        implements Cloneable
045    {
046        /** The Plexus component type */
047        public static final String MAVEN_PLUGIN = "maven-plugin";
048    
049        /** "once-per-session" execution strategy */
050        public static final String SINGLE_PASS_EXEC_STRATEGY = "once-per-session";
051    
052        /** "always" execution strategy */
053        public static final String MULTI_PASS_EXEC_STRATEGY = "always";
054    
055        private static final String DEFAULT_INSTANTIATION_STRATEGY = "per-lookup";
056    
057        private static final String DEFAULT_LANGUAGE = "java";
058    
059        private List<Parameter> parameters;
060    
061        private Map<String, Parameter> parameterMap;
062    
063        /** By default, the execution strategy is "once-per-session" */
064        private String executionStrategy = SINGLE_PASS_EXEC_STRATEGY;
065    
066        /**
067         * The goal name for the Mojo, that users will reference from the command line to execute the Mojo directly, or
068         * inside a POM in order to provide Mojo-specific configuration.
069         */
070        private String goal;
071    
072        /**
073         * Defines a default phase to bind a mojo execution to if the user does not explicitly set a phase in the POM.
074         * <i>Note:</i> This will not automagically make a mojo run when the plugin declaration is added to the POM. It
075         * merely enables the user to omit the <code>&lt;phase&gt;</code> element from the surrounding
076         * <code>&lt;execution&gt;</code> element.
077         */
078        private String phase;
079    
080        /** Specify the version when the Mojo was added to the API. Similar to Javadoc since. */
081        private String since;
082    
083        /** Reference the invocation phase of the Mojo. */
084        private String executePhase;
085    
086        /** Reference the invocation goal of the Mojo. */
087        private String executeGoal;
088    
089        /** Reference the invocation lifecycle of the Mojo. */
090        private String executeLifecycle;
091    
092        /**
093         * Specify the version when the Mojo was deprecated to the API. Similar to Javadoc deprecated. This will trigger a
094         * warning when a user tries to configure a parameter marked as deprecated.
095         */
096        private String deprecated;
097    
098        /**
099         * Flags this Mojo to run it in a multi module way, i.e. aggregate the build with the set of projects listed as
100         * modules. By default, no need to aggregate the Maven project and its child modules
101         */
102        private boolean aggregator = false;
103    
104        // ----------------------------------------------------------------------
105        //
106        // ----------------------------------------------------------------------
107    
108        /** Specify the required dependencies in a specified scope */
109        private String dependencyResolutionRequired = null;
110    
111        /**
112         * The scope of (transitive) dependencies that should be collected but not resolved.
113         * @since 3.0-alpha-3
114         */
115        private String dependencyCollectionRequired;
116    
117        /**  By default, the Mojo needs a Maven project to be executed */
118        private boolean projectRequired = true;
119    
120        /**  By default, the Mojo is assumed to work offline as well */
121        private boolean onlineRequired = false;
122    
123        /**  Plugin configuration */
124        private PlexusConfiguration mojoConfiguration;
125    
126        /**  Plugin descriptor */
127        private PluginDescriptor pluginDescriptor;
128    
129        /**  By default, the Mojo is inherited */
130        private boolean inheritedByDefault = true;
131    
132        /**  By default, the Mojo cannot be invoked directly */
133        private boolean directInvocationOnly = false;
134    
135        /**  By default, the Mojo don't need reports to run */
136        private boolean requiresReports = false;
137    
138        /**
139         * By default, mojos are not threadsafe
140         * @since 3.0-beta-2
141         */
142        private boolean threadSafe = false;
143    
144        /**
145         * Default constructor.
146         */
147        public MojoDescriptor()
148        {
149            setInstantiationStrategy( DEFAULT_INSTANTIATION_STRATEGY );
150            setComponentFactory( DEFAULT_LANGUAGE );
151        }
152    
153        // ----------------------------------------------------------------------
154        //
155        // ----------------------------------------------------------------------
156    
157        /**
158         * @return the language of this Mojo, i.e. <code>java</code>
159         */
160        public String getLanguage()
161        {
162            return getComponentFactory();
163        }
164    
165        /**
166         * @param language the new language
167         */
168        public void setLanguage( String language )
169        {
170            setComponentFactory( language );
171        }
172    
173        /**
174         * @return <code>true</code> if the Mojo is deprecated, <code>false</code> otherwise.
175         */
176        public String getDeprecated()
177        {
178            return deprecated;
179        }
180    
181        /**
182         * @param deprecated <code>true</code> to deprecate the Mojo, <code>false</code> otherwise.
183         */
184        public void setDeprecated( String deprecated )
185        {
186            this.deprecated = deprecated;
187        }
188    
189        /**
190         * @return the list of parameters
191         */
192        public List<Parameter> getParameters()
193        {
194            return 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            for ( Parameter parameter : parameters )
205            {
206                addParameter( parameter );
207            }
208        }
209    
210        /**
211         * @param parameter add a new parameter
212         * @throws DuplicateParameterException if any
213         */
214        public void addParameter( Parameter parameter )
215            throws DuplicateParameterException
216        {
217            if ( parameters != null && parameters.contains( parameter ) )
218            {
219                throw new DuplicateParameterException( parameter.getName()
220                    + " has been declared multiple times in mojo with goal: " + getGoal() + " (implementation: "
221                    + getImplementation() + ")" );
222            }
223    
224            if ( parameters == null )
225            {
226                parameters = new LinkedList<Parameter>();
227            }
228    
229            parameters.add( parameter );
230        }
231    
232        /**
233         * @return the list parameters as a Map
234         */
235        public Map<String, Parameter> getParameterMap()
236        {
237            if ( parameterMap == null )
238            {
239                parameterMap = new HashMap<String, Parameter>();
240    
241                if ( parameters != null )
242                {
243                    for ( Parameter pd : parameters )
244                    {
245                        parameterMap.put( pd.getName(), pd );
246                    }
247                }
248            }
249    
250            return parameterMap;
251        }
252    
253        // ----------------------------------------------------------------------
254        // Dependency requirement
255        // ----------------------------------------------------------------------
256    
257        /**
258         * @param requiresDependencyResolution the new required dependencies in a specified scope
259         */
260        public void setDependencyResolutionRequired( String requiresDependencyResolution )
261        {
262            this.dependencyResolutionRequired = requiresDependencyResolution;
263        }
264    
265        public String getDependencyResolutionRequired()
266        {
267            return dependencyResolutionRequired;
268        }
269    
270        /**
271         * @return the required dependencies in a specified scope
272         * @TODO the name is not intelligible
273         */
274        @Deprecated
275        public String isDependencyResolutionRequired()
276        {
277            return dependencyResolutionRequired;
278        }
279    
280        /**
281         * @since 3.0-alpha-3
282         */
283        public void setDependencyCollectionRequired( String requiresDependencyCollection )
284        {
285            this.dependencyCollectionRequired = requiresDependencyCollection;
286        }
287    
288        /**
289         * Gets the scope of (transitive) dependencies that should be collected. Dependency collection refers to the process
290         * of calculating the complete dependency tree in terms of artifact coordinates. In contrast to dependency
291         * resolution, this does not include the download of the files for the dependency artifacts. It is meant for mojos
292         * that only want to analyze the set of transitive dependencies, in particular during early lifecycle phases where
293         * full dependency resolution might fail due to projects which haven't been built yet.
294         * 
295         * @return The scope of (transitive) dependencies that should be collected or {@code null} if none.
296         * @since 3.0-alpha-3
297         */
298        public String getDependencyCollectionRequired()
299        {
300            return dependencyCollectionRequired;
301        }
302    
303        // ----------------------------------------------------------------------
304        // Project requirement
305        // ----------------------------------------------------------------------
306    
307        /**
308         * @param requiresProject <code>true</code> if the Mojo needs a Maven project to be executed, <code>false</code>
309         * otherwise.
310         */
311        public void setProjectRequired( boolean requiresProject )
312        {
313            this.projectRequired = requiresProject;
314        }
315    
316        /**
317         * @return <code>true</code> if the Mojo needs a Maven project to be executed, <code>false</code> otherwise.
318         */
319        public boolean isProjectRequired()
320        {
321            return projectRequired;
322        }
323    
324        // ----------------------------------------------------------------------
325        // Online vs. Offline requirement
326        // ----------------------------------------------------------------------
327    
328        /**
329         * @param requiresOnline <code>true</code> if the Mojo is online, <code>false</code> otherwise.
330         */
331        public void setOnlineRequired( boolean requiresOnline )
332        {
333            this.onlineRequired = requiresOnline;
334        }
335    
336        /**
337         * @return <code>true</code> if the Mojo is online, <code>false</code> otherwise.
338         */
339        // blech! this isn't even intelligible as a method name. provided for
340        // consistency...
341        public boolean isOnlineRequired()
342        {
343            return onlineRequired;
344        }
345    
346        /**
347         * @return <code>true</code> if the Mojo is online, <code>false</code> otherwise.
348         */
349        // more english-friendly method...keep the code clean! :)
350        public boolean requiresOnline()
351        {
352            return onlineRequired;
353        }
354    
355        /**
356         * @return the binded phase name of the Mojo
357         */
358        public String getPhase()
359        {
360            return phase;
361        }
362    
363        /**
364         * @param phase the new binded phase name of the Mojo
365         */
366        public void setPhase( String phase )
367        {
368            this.phase = phase;
369        }
370    
371        /**
372         * @return the version when the Mojo was added to the API
373         */
374        public String getSince()
375        {
376            return since;
377        }
378    
379        /**
380         * @param since the new version when the Mojo was added to the API
381         */
382        public void setSince( String since )
383        {
384            this.since = since;
385        }
386    
387        /**
388         * @return The goal name of the Mojo
389         */
390        public String getGoal()
391        {
392            return goal;
393        }
394    
395        /**
396         * @param goal The new goal name of the Mojo
397         */
398        public void setGoal( String goal )
399        {
400            this.goal = goal;
401        }
402    
403        /**
404         * @return the invocation phase of the Mojo
405         */
406        public String getExecutePhase()
407        {
408            return executePhase;
409        }
410    
411        /**
412         * @param executePhase the new invocation phase of the Mojo
413         */
414        public void setExecutePhase( String executePhase )
415        {
416            this.executePhase = executePhase;
417        }
418    
419        /**
420         * @return <code>true</code> if the Mojo uses <code>always</code> for the <code>executionStrategy</code>
421         */
422        public boolean alwaysExecute()
423        {
424            return MULTI_PASS_EXEC_STRATEGY.equals( executionStrategy );
425        }
426    
427        /**
428         * @return the execution strategy
429         */
430        public String getExecutionStrategy()
431        {
432            return executionStrategy;
433        }
434    
435        /**
436         * @param executionStrategy the new execution strategy
437         */
438        public void setExecutionStrategy( String executionStrategy )
439        {
440            this.executionStrategy = executionStrategy;
441        }
442    
443        /**
444         * @return the mojo configuration
445         */
446        public PlexusConfiguration getMojoConfiguration()
447        {
448            if ( mojoConfiguration == null )
449            {
450                mojoConfiguration = new XmlPlexusConfiguration( "configuration" );
451            }
452            return mojoConfiguration;
453        }
454    
455        /**
456         * @param mojoConfiguration a new mojo configuration
457         */
458        public void setMojoConfiguration( PlexusConfiguration mojoConfiguration )
459        {
460            this.mojoConfiguration = mojoConfiguration;
461        }
462    
463        /** {@inheritDoc} */
464        public String getRole()
465        {
466            return Mojo.ROLE;
467        }
468    
469        /** {@inheritDoc} */
470        public String getRoleHint()
471        {
472            return getId();
473        }
474    
475        /**
476         * @return the id of the mojo, based on the goal name
477         */
478        public String getId()
479        {
480            return getPluginDescriptor().getId() + ":" + getGoal();
481        }
482    
483        /**
484         * @return the full goal name
485         * @see PluginDescriptor#getGoalPrefix()
486         * @see #getGoal()
487         */
488        public String getFullGoalName()
489        {
490            return getPluginDescriptor().getGoalPrefix() + ":" + getGoal();
491        }
492    
493        /** {@inheritDoc} */
494        public String getComponentType()
495        {
496            return MAVEN_PLUGIN;
497        }
498    
499        /**
500         * @return the plugin descriptor
501         */
502        public PluginDescriptor getPluginDescriptor()
503        {
504            return pluginDescriptor;
505        }
506    
507        /**
508         * @param pluginDescriptor the new plugin descriptor
509         */
510        public void setPluginDescriptor( PluginDescriptor pluginDescriptor )
511        {
512            this.pluginDescriptor = pluginDescriptor;
513        }
514    
515        /**
516         * @return <code>true</code> if the Mojo is herited, <code>false</code> otherwise.
517         */
518        public boolean isInheritedByDefault()
519        {
520            return inheritedByDefault;
521        }
522    
523        /**
524         * @param inheritedByDefault <code>true</code> if the Mojo is herited, <code>false</code> otherwise.
525         */
526        public void setInheritedByDefault( boolean inheritedByDefault )
527        {
528            this.inheritedByDefault = inheritedByDefault;
529        }
530    
531        /** {@inheritDoc} */
532        public boolean equals( Object object )
533        {
534            if ( this == object )
535            {
536                return true;
537            }
538    
539            if ( object instanceof MojoDescriptor )
540            {
541                MojoDescriptor other = (MojoDescriptor) object;
542    
543                if ( !compareObjects( getPluginDescriptor(), other.getPluginDescriptor() ) )
544                {
545                    return false;
546                }
547    
548                return compareObjects( getGoal(), other.getGoal() );
549    
550            }
551    
552            return false;
553        }
554    
555        private boolean compareObjects( Object first, Object second )
556        {
557            if ( ( first == null && second != null ) || ( first != null && second == null ) )
558            {
559                return false;
560            }
561    
562            return first.equals( second );
563        }
564    
565        /** {@inheritDoc} */
566        public int hashCode()
567        {
568            int result = 1;
569    
570            String goal = getGoal();
571    
572            if ( goal != null )
573            {
574                result += goal.hashCode();
575            }
576    
577            PluginDescriptor pd = getPluginDescriptor();
578    
579            if ( pd != null )
580            {
581                result -= pd.hashCode();
582            }
583    
584            return result;
585        }
586    
587        /**
588         * @return the invocation lifecycle of the Mojo
589         */
590        public String getExecuteLifecycle()
591        {
592            return executeLifecycle;
593        }
594    
595        /**
596         * @param executeLifecycle the new invocation lifecycle of the Mojo
597         */
598        public void setExecuteLifecycle( String executeLifecycle )
599        {
600            this.executeLifecycle = executeLifecycle;
601        }
602    
603        /**
604         * @param aggregator <code>true</code> if the Mojo uses the Maven project and its child modules,
605         * <code>false</code> otherwise.
606         */
607        public void setAggregator( boolean aggregator )
608        {
609            this.aggregator = aggregator;
610        }
611    
612        /**
613         * @return <code>true</code> if the Mojo uses the Maven project and its child modules,
614         * <code>false</code> otherwise.
615         */
616        public boolean isAggregator()
617        {
618            return aggregator;
619        }
620    
621        /**
622         * @return <code>true</code> if the Mojo cannot be invoked directly, <code>false</code> otherwise.
623         */
624        public boolean isDirectInvocationOnly()
625        {
626            return directInvocationOnly;
627        }
628    
629        /**
630         * @param directInvocationOnly <code>true</code> if the Mojo cannot be invoked directly,
631         * <code>false</code> otherwise.
632         */
633        public void setDirectInvocationOnly( boolean directInvocationOnly )
634        {
635            this.directInvocationOnly = directInvocationOnly;
636        }
637    
638        /**
639         * @return <code>true</code> if the Mojo needs reports to run, <code>false</code> otherwise.
640         */
641        public boolean isRequiresReports()
642        {
643            return requiresReports;
644        }
645    
646        /**
647         * @param requiresReports <code>true</code> if the Mojo needs reports to run, <code>false</code> otherwise.
648         */
649        public void setRequiresReports( boolean requiresReports )
650        {
651            this.requiresReports = requiresReports;
652        }
653    
654        /**
655         * @param executeGoal the new invocation goal of the Mojo
656         */
657        public void setExecuteGoal( String executeGoal )
658        {
659            this.executeGoal = executeGoal;
660        }
661    
662        /**
663         * @return the invocation goal of the Mojo
664         */
665        public String getExecuteGoal()
666        {
667            return executeGoal;
668        }
669    
670    
671        /**
672         * @return True if the <code>Mojo</code> is thread-safe and can be run safely in parallel
673         * @since 3.0-beta-2
674         */
675        public boolean isThreadSafe()
676        {
677            return threadSafe;
678        }
679    
680        /**
681         * @param threadSafe indicates that the mojo is thread-safe and can be run safely in parallel
682         * @since 3.0-beta-2
683         */
684        public void setThreadSafe( boolean threadSafe )
685        {
686            this.threadSafe = threadSafe;
687        }
688    
689        /**
690         * @return {@code true} if this mojo forks either a goal or the lifecycle, {@code false} otherwise.
691         */
692        public boolean isForking()
693        {
694            return ( getExecuteGoal() != null && getExecuteGoal().length() > 0 )
695                || ( getExecutePhase() != null && getExecutePhase().length() > 0 );
696        }
697    
698        /**
699         * Creates a shallow copy of this mojo descriptor.
700         */
701        @Override
702        public MojoDescriptor clone()
703        {
704            try
705            {
706                return (MojoDescriptor) super.clone();
707            }
708            catch ( CloneNotSupportedException e )
709            {
710                throw new UnsupportedOperationException( e );
711            }
712        }
713    
714    }