1 package org.apache.maven.plugin.descriptor;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import java.util.ArrayList;
23 import java.util.LinkedHashMap;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Objects;
27
28 import org.apache.maven.plugin.Mojo;
29 import org.codehaus.plexus.component.repository.ComponentDescriptor;
30 import org.codehaus.plexus.configuration.PlexusConfiguration;
31 import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
32
33 /**
34 * The bean containing the Mojo descriptor.<br>
35 * For more information about the usage tag, have a look to:
36 * <a href="https://maven.apache.org/developers/mojo-api-specification.html">
37 * https://maven.apache.org/developers/mojo-api-specification.html</a>
38 *
39 * TODO is there a need for the delegation of MavenMojoDescriptor to this?
40 * Why not just extend ComponentDescriptor here?
41 */
42 public class MojoDescriptor
43 extends ComponentDescriptor<Mojo>
44 implements Cloneable
45 {
46 /** The Plexus component type */
47 public static final String MAVEN_PLUGIN = "maven-plugin";
48
49 /** "once-per-session" execution strategy */
50 public static final String SINGLE_PASS_EXEC_STRATEGY = "once-per-session";
51
52 /** "always" execution strategy */
53 public static final String MULTI_PASS_EXEC_STRATEGY = "always";
54
55 private static final String DEFAULT_INSTANTIATION_STRATEGY = "per-lookup";
56
57 private static final String DEFAULT_LANGUAGE = "java";
58
59 private final ArrayList<Parameter> parameters;
60
61 /** By default, the execution strategy is "once-per-session" */
62 private String executionStrategy = SINGLE_PASS_EXEC_STRATEGY;
63
64 /**
65 * The goal name for the Mojo, that users will reference from the command line to execute the Mojo directly, or
66 * inside a POM in order to provide Mojo-specific configuration.
67 */
68 private String goal;
69
70 /**
71 * Defines a default phase to bind a mojo execution to if the user does not explicitly set a phase in the POM.
72 * <i>Note:</i> This will not automagically make a mojo run when the plugin declaration is added to the POM. It
73 * merely enables the user to omit the <code><phase></code> element from the surrounding
74 * <code><execution></code> element.
75 */
76 private String phase;
77
78 /** Specify the version when the Mojo was added to the API. Similar to Javadoc since. */
79 private String since;
80
81 /** Reference the invocation phase of the Mojo. */
82 private String executePhase;
83
84 /** Reference the invocation goal of the Mojo. */
85 private String executeGoal;
86
87 /** Reference the invocation lifecycle of the Mojo. */
88 private String executeLifecycle;
89
90 /**
91 * Description with reason of Mojo deprecation. Similar to Javadoc {@code @deprecated}.
92 * This will trigger a warning when a user tries to use a Mojo marked as deprecated.
93 */
94 private String deprecated;
95
96 /**
97 * Flags this Mojo to run it in a multi-module way, i.e. aggregate the build with the set of projects listed as
98 * modules. By default, no need to aggregate the Maven project and its child modules
99 */
100 private boolean aggregator = false;
101
102 // ----------------------------------------------------------------------
103 //
104 // ----------------------------------------------------------------------
105
106 /** Specify the required dependencies in a specified scope */
107 private String dependencyResolutionRequired = null;
108
109 /**
110 * The scope of (transitive) dependencies that should be collected but not resolved.
111 * @since 3.0-alpha-3
112 */
113 private String dependencyCollectionRequired;
114
115 /** By default, the Mojo needs a Maven project to be executed */
116 private boolean projectRequired = true;
117
118 /** By default, the Mojo is assumed to work offline as well */
119 private boolean onlineRequired = false;
120
121 /** Plugin configuration */
122 private PlexusConfiguration mojoConfiguration;
123
124 /** Plugin descriptor */
125 private PluginDescriptor pluginDescriptor;
126
127 /** By default, the Mojo is inherited */
128 private boolean inheritedByDefault = true;
129
130 /** By default, the Mojo cannot be invoked directly */
131 private boolean directInvocationOnly = false;
132
133 /** By default, the Mojo don't need reports to run */
134 private boolean requiresReports = false;
135
136 /**
137 * By default, mojos are not threadsafe
138 * @since 3.0-beta-2
139 */
140 private boolean threadSafe = false;
141
142 private boolean v4Api = false;
143
144 /**
145 * Default constructor.
146 */
147 public MojoDescriptor()
148 {
149 this.parameters = new ArrayList<>();
150 setInstantiationStrategy( DEFAULT_INSTANTIATION_STRATEGY );
151 setComponentFactory( DEFAULT_LANGUAGE );
152 }
153
154 // ----------------------------------------------------------------------
155 //
156 // ----------------------------------------------------------------------
157
158 /**
159 * @return the language of this Mojo, i.e. <code>java</code>
160 */
161 public String getLanguage()
162 {
163 return getComponentFactory();
164 }
165
166 /**
167 * @param language the new language
168 */
169 public void setLanguage( String language )
170 {
171 setComponentFactory( language );
172 }
173
174 /**
175 * @return Description with reason of a Mojo deprecation.
176 */
177 public String getDeprecated()
178 {
179 return deprecated;
180 }
181
182 /**
183 * @param deprecated Description with reason of a Mojo deprecation.
184 */
185 public void setDeprecated( String deprecated )
186 {
187 this.deprecated = deprecated;
188 }
189
190 /**
191 * @return the list of parameters copy. Any change to returned list is NOT reflected on this instance. To add
192 * parameters, use {@link #addParameter(Parameter)} method.
193 */
194 public List<Parameter> getParameters()
195 {
196 return new ArrayList<>( parameters );
197 }
198
199 /**
200 * @param parameters the new list of parameters
201 * @throws DuplicateParameterException if any
202 */
203 public void setParameters( List<Parameter> parameters )
204 throws DuplicateParameterException
205 {
206 this.parameters.clear();
207 for ( Parameter parameter : parameters )
208 {
209 addParameter( parameter );
210 }
211 }
212
213 /**
214 * @param parameter add a new parameter
215 * @throws DuplicateParameterException if any
216 */
217 public void addParameter( Parameter parameter )
218 throws DuplicateParameterException
219 {
220 if ( parameters.contains( parameter ) )
221 {
222 throw new DuplicateParameterException( parameter.getName()
223 + " has been declared multiple times in mojo with goal: " + getGoal() + " (implementation: "
224 + getImplementation() + ")" );
225 }
226
227 parameters.add( parameter );
228 }
229
230 /**
231 * @return the list parameters as a Map (keyed by {@link Parameter#getName()}) that is built from
232 * {@link #parameters} list on each call. In other words, the map returned is built on fly and is a copy.
233 * Any change to this map is NOT reflected on list and other way around!
234 */
235 public Map<String, Parameter> getParameterMap()
236 {
237 LinkedHashMap<String, Parameter> parameterMap = new LinkedHashMap<>();
238
239 for ( Parameter pd : parameters )
240 {
241 parameterMap.put( pd.getName(), pd );
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 /**
275 * @since 3.0-alpha-3
276 */
277 public void setDependencyCollectionRequired( String requiresDependencyCollection )
278 {
279 this.dependencyCollectionRequired = requiresDependencyCollection;
280 }
281
282 /**
283 * Gets the scope of (transitive) dependencies that should be collected. Dependency collection refers to the process
284 * of calculating the complete dependency tree in terms of artifact coordinates. In contrast to dependency
285 * resolution, this does not include the download of the files for the dependency artifacts. It is meant for mojos
286 * that only want to analyze the set of transitive dependencies, in particular during early lifecycle phases where
287 * full dependency resolution might fail due to projects which haven't been built yet.
288 *
289 * @return The scope of (transitive) dependencies that should be collected or {@code null} if none.
290 * @since 3.0-alpha-3
291 */
292 public String getDependencyCollectionRequired()
293 {
294 return dependencyCollectionRequired;
295 }
296
297 // ----------------------------------------------------------------------
298 // Project requirement
299 // ----------------------------------------------------------------------
300
301 /**
302 * @param requiresProject <code>true</code> if the Mojo needs a Maven project to be executed, <code>false</code>
303 * otherwise.
304 */
305 public void setProjectRequired( boolean requiresProject )
306 {
307 this.projectRequired = requiresProject;
308 }
309
310 /**
311 * @return <code>true</code> if the Mojo needs a Maven project to be executed, <code>false</code> otherwise.
312 */
313 public boolean isProjectRequired()
314 {
315 return projectRequired;
316 }
317
318 // ----------------------------------------------------------------------
319 // Online vs. Offline requirement
320 // ----------------------------------------------------------------------
321
322 /**
323 * @param requiresOnline <code>true</code> if the Mojo is online, <code>false</code> otherwise.
324 */
325 public void setOnlineRequired( boolean requiresOnline )
326 {
327 this.onlineRequired = requiresOnline;
328 }
329
330 /**
331 * @return <code>true</code> if the Mojo is online, <code>false</code> otherwise.
332 */
333 // blech! this isn't even intelligible as a method name. provided for
334 // consistency...
335 public boolean isOnlineRequired()
336 {
337 return onlineRequired;
338 }
339
340 /**
341 * @return <code>true</code> if the Mojo is online, <code>false</code> otherwise.
342 */
343 // more english-friendly method...keep the code clean! :)
344 public boolean requiresOnline()
345 {
346 return onlineRequired;
347 }
348
349 /**
350 * @return the bound phase name of the Mojo
351 */
352 public String getPhase()
353 {
354 return phase;
355 }
356
357 /**
358 * @param phase the new bound phase name of the Mojo
359 */
360 public void setPhase( String phase )
361 {
362 this.phase = phase;
363 }
364
365 /**
366 * @return the version when the Mojo was added to the API
367 */
368 public String getSince()
369 {
370 return since;
371 }
372
373 /**
374 * @param since the new version when the Mojo was added to the API
375 */
376 public void setSince( String since )
377 {
378 this.since = since;
379 }
380
381 /**
382 * @return The goal name of the Mojo
383 */
384 public String getGoal()
385 {
386 return goal;
387 }
388
389 /**
390 * @param goal The new goal name of the Mojo
391 */
392 public void setGoal( String goal )
393 {
394 this.goal = goal;
395 }
396
397 /**
398 * @return the invocation phase of the Mojo
399 */
400 public String getExecutePhase()
401 {
402 return executePhase;
403 }
404
405 /**
406 * @param executePhase the new invocation phase of the Mojo
407 */
408 public void setExecutePhase( String executePhase )
409 {
410 this.executePhase = executePhase;
411 }
412
413 /**
414 * @return <code>true</code> if the Mojo uses <code>always</code> for the <code>executionStrategy</code>
415 */
416 public boolean alwaysExecute()
417 {
418 return MULTI_PASS_EXEC_STRATEGY.equals( executionStrategy );
419 }
420
421 /**
422 * @return the execution strategy
423 */
424 public String getExecutionStrategy()
425 {
426 return executionStrategy;
427 }
428
429 /**
430 * @param executionStrategy the new execution strategy
431 */
432 public void setExecutionStrategy( String executionStrategy )
433 {
434 this.executionStrategy = executionStrategy;
435 }
436
437 /**
438 * @return the mojo configuration
439 */
440 public PlexusConfiguration getMojoConfiguration()
441 {
442 if ( mojoConfiguration == null )
443 {
444 mojoConfiguration = new XmlPlexusConfiguration( "configuration" );
445 }
446 return mojoConfiguration;
447 }
448
449 /**
450 * @param mojoConfiguration a new mojo configuration
451 */
452 public void setMojoConfiguration( PlexusConfiguration mojoConfiguration )
453 {
454 this.mojoConfiguration = mojoConfiguration;
455 }
456
457 /** {@inheritDoc} */
458 public String getRole()
459 {
460 return isV4Api() ? "org.apache.maven.api.plugin.Mojo" : Mojo.ROLE;
461 }
462
463 /** {@inheritDoc} */
464 public String getRoleHint()
465 {
466 return getId();
467 }
468
469 /**
470 * @return the id of the mojo, based on the goal name
471 */
472 public String getId()
473 {
474 return getPluginDescriptor().getId() + ":" + getGoal();
475 }
476
477 /**
478 * @return the full goal name
479 * @see PluginDescriptor#getGoalPrefix()
480 * @see #getGoal()
481 */
482 public String getFullGoalName()
483 {
484 return getPluginDescriptor().getGoalPrefix() + ":" + getGoal();
485 }
486
487 /** {@inheritDoc} */
488 public String getComponentType()
489 {
490 return MAVEN_PLUGIN;
491 }
492
493 /**
494 * @return the plugin descriptor
495 */
496 public PluginDescriptor getPluginDescriptor()
497 {
498 return pluginDescriptor;
499 }
500
501 /**
502 * @param pluginDescriptor the new plugin descriptor
503 */
504 public void setPluginDescriptor( PluginDescriptor pluginDescriptor )
505 {
506 this.pluginDescriptor = pluginDescriptor;
507 }
508
509 /**
510 * @return <code>true</code> if the Mojo is inherited, <code>false</code> otherwise.
511 */
512 public boolean isInheritedByDefault()
513 {
514 return inheritedByDefault;
515 }
516
517 /**
518 * @param inheritedByDefault <code>true</code> if the Mojo is inherited, <code>false</code> otherwise.
519 */
520 public void setInheritedByDefault( boolean inheritedByDefault )
521 {
522 this.inheritedByDefault = inheritedByDefault;
523 }
524
525 /** {@inheritDoc} */
526 public boolean equals( Object object )
527 {
528 if ( this == object )
529 {
530 return true;
531 }
532
533 if ( object instanceof MojoDescriptor )
534 {
535 MojoDescriptor other = (MojoDescriptor) object;
536
537 return Objects.equals( getPluginDescriptor(), other.getPluginDescriptor() )
538 && Objects.equals( getGoal(), other.getGoal() );
539 }
540
541 return false;
542 }
543
544 /** {@inheritDoc} */
545 public int hashCode()
546 {
547 return Objects.hash( getGoal(), getPluginDescriptor() );
548 }
549
550 /**
551 * @return the invocation lifecycle of the Mojo
552 */
553 public String getExecuteLifecycle()
554 {
555 return executeLifecycle;
556 }
557
558 /**
559 * @param executeLifecycle the new invocation lifecycle of the Mojo
560 */
561 public void setExecuteLifecycle( String executeLifecycle )
562 {
563 this.executeLifecycle = executeLifecycle;
564 }
565
566 /**
567 * @param aggregator <code>true</code> if the Mojo uses the Maven project and its child modules,
568 * <code>false</code> otherwise.
569 */
570 public void setAggregator( boolean aggregator )
571 {
572 this.aggregator = aggregator;
573 }
574
575 /**
576 * @return <code>true</code> if the Mojo uses the Maven project and its child modules,
577 * <code>false</code> otherwise.
578 */
579 public boolean isAggregator()
580 {
581 return aggregator;
582 }
583
584 /**
585 * @return <code>true</code> if the Mojo cannot be invoked directly, <code>false</code> otherwise.
586 */
587 public boolean isDirectInvocationOnly()
588 {
589 return directInvocationOnly;
590 }
591
592 /**
593 * @param directInvocationOnly <code>true</code> if the Mojo cannot be invoked directly,
594 * <code>false</code> otherwise.
595 */
596 public void setDirectInvocationOnly( boolean directInvocationOnly )
597 {
598 this.directInvocationOnly = directInvocationOnly;
599 }
600
601 /**
602 * @return <code>true</code> if the Mojo needs reports to run, <code>false</code> otherwise.
603 */
604 public boolean isRequiresReports()
605 {
606 return requiresReports;
607 }
608
609 /**
610 * @param requiresReports <code>true</code> if the Mojo needs reports to run, <code>false</code> otherwise.
611 */
612 public void setRequiresReports( boolean requiresReports )
613 {
614 this.requiresReports = requiresReports;
615 }
616
617 /**
618 * @param executeGoal the new invocation goal of the Mojo
619 */
620 public void setExecuteGoal( String executeGoal )
621 {
622 this.executeGoal = executeGoal;
623 }
624
625 /**
626 * @return the invocation goal of the Mojo
627 */
628 public String getExecuteGoal()
629 {
630 return executeGoal;
631 }
632
633
634 /**
635 * @return True if the <code>Mojo</code> is thread-safe and can be run safely in parallel
636 * @since 3.0-beta-2
637 */
638 public boolean isThreadSafe()
639 {
640 return threadSafe;
641 }
642
643 /**
644 * @param threadSafe indicates that the mojo is thread-safe and can be run safely in parallel
645 * @since 3.0-beta-2
646 */
647 public void setThreadSafe( boolean threadSafe )
648 {
649 this.threadSafe = threadSafe;
650 }
651
652 /**
653 * @return {@code true} if this mojo forks either a goal or the lifecycle, {@code false} otherwise.
654 */
655 public boolean isForking()
656 {
657 return ( getExecuteGoal() != null && getExecuteGoal().length() > 0 )
658 || ( getExecutePhase() != null && getExecutePhase().length() > 0 );
659 }
660
661 public boolean isV4Api()
662 {
663 return v4Api;
664 }
665
666 public void setV4Api( boolean v4Api )
667 {
668 this.v4Api = v4Api;
669 }
670
671 /**
672 * Creates a shallow copy of this mojo descriptor.
673 */
674 @Override
675 public MojoDescriptor clone()
676 {
677 try
678 {
679 return (MojoDescriptor) super.clone();
680 }
681 catch ( CloneNotSupportedException e )
682 {
683 throw new UnsupportedOperationException( e );
684 }
685 }
686
687 }