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