001package 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
022import java.util.HashMap;
023import java.util.LinkedList;
024import java.util.List;
025import java.util.Map;
026
027import org.apache.maven.plugin.Mojo;
028import org.codehaus.plexus.component.repository.ComponentDescriptor;
029import org.codehaus.plexus.configuration.PlexusConfiguration;
030import 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 */
042public 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}