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