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