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