| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.maven.plugin.descriptor; |
| |
| import java.util.ArrayList; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Objects; |
| import java.util.stream.Collectors; |
| |
| import org.apache.maven.plugin.Mojo; |
| import org.codehaus.plexus.component.repository.ComponentDescriptor; |
| import org.codehaus.plexus.configuration.PlexusConfiguration; |
| import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration; |
| |
| /** |
| * The bean containing the Mojo descriptor.<br> |
| * For more information about the usage tag, have a look to: |
| * <a href="https://maven.apache.org/developers/mojo-api-specification.html"> |
| * https://maven.apache.org/developers/mojo-api-specification.html</a> |
| * |
| * TODO is there a need for the delegation of MavenMojoDescriptor to this? |
| * Why not just extend ComponentDescriptor here? |
| */ |
| public class MojoDescriptor extends ComponentDescriptor<Mojo> implements Cloneable { |
| /** The Plexus component type */ |
| public static final String MAVEN_PLUGIN = "maven-plugin"; |
| |
| /** "once-per-session" execution strategy */ |
| public static final String SINGLE_PASS_EXEC_STRATEGY = "once-per-session"; |
| |
| /** "always" execution strategy */ |
| public static final String MULTI_PASS_EXEC_STRATEGY = "always"; |
| |
| private static final String DEFAULT_INSTANTIATION_STRATEGY = "per-lookup"; |
| |
| private static final String DEFAULT_LANGUAGE = "java"; |
| |
| private final ArrayList<Parameter> parameters; |
| |
| /** By default, the execution strategy is "once-per-session" */ |
| private String executionStrategy = SINGLE_PASS_EXEC_STRATEGY; |
| |
| /** |
| * The goal name for the Mojo, that users will reference from the command line to execute the Mojo directly, or |
| * inside a POM in order to provide Mojo-specific configuration. |
| */ |
| private String goal; |
| |
| /** |
| * Defines a default phase to bind a mojo execution to if the user does not explicitly set a phase in the POM. |
| * <i>Note:</i> This will not automagically make a mojo run when the plugin declaration is added to the POM. It |
| * merely enables the user to omit the <code><phase></code> element from the surrounding |
| * <code><execution></code> element. |
| */ |
| private String phase; |
| |
| /** Specify the version when the Mojo was added to the API. Similar to Javadoc since. */ |
| private String since; |
| |
| /** Reference the invocation phase of the Mojo. */ |
| private String executePhase; |
| |
| /** Reference the invocation goal of the Mojo. */ |
| private String executeGoal; |
| |
| /** Reference the invocation lifecycle of the Mojo. */ |
| private String executeLifecycle; |
| |
| /** |
| * Description with reason of Mojo deprecation. Similar to Javadoc {@code @deprecated}. |
| * This will trigger a warning when a user tries to use a Mojo marked as deprecated. |
| */ |
| private String deprecated; |
| |
| /** |
| * Flags this Mojo to run it in a multi-module way, i.e. aggregate the build with the set of projects listed as |
| * modules. By default, no need to aggregate the Maven project and its child modules |
| */ |
| private boolean aggregator = false; |
| |
| // ---------------------------------------------------------------------- |
| // |
| // ---------------------------------------------------------------------- |
| |
| /** Specify the required dependencies in a specified scope */ |
| private String dependencyResolutionRequired = null; |
| |
| /** |
| * The scope of (transitive) dependencies that should be collected but not resolved. |
| * @since 3.0-alpha-3 |
| */ |
| private String dependencyCollectionRequired; |
| |
| /** By default, the Mojo needs a Maven project to be executed */ |
| private boolean projectRequired = true; |
| |
| /** By default, the Mojo is assumed to work offline as well */ |
| private boolean onlineRequired = false; |
| |
| /** Plugin configuration */ |
| private PlexusConfiguration mojoConfiguration; |
| |
| /** Plugin descriptor */ |
| private PluginDescriptor pluginDescriptor; |
| |
| /** By default, the Mojo is inherited */ |
| private boolean inheritedByDefault = true; |
| |
| /** By default, the Mojo cannot be invoked directly */ |
| private boolean directInvocationOnly = false; |
| |
| /** By default, the Mojo don't need reports to run */ |
| private boolean requiresReports = false; |
| |
| /** |
| * By default, mojos are not threadsafe |
| * @since 3.0-beta-2 |
| */ |
| private boolean threadSafe = false; |
| |
| private boolean v4Api = false; |
| |
| /** |
| * Default constructor. |
| */ |
| public MojoDescriptor() { |
| this.parameters = new ArrayList<>(); |
| setInstantiationStrategy(DEFAULT_INSTANTIATION_STRATEGY); |
| setComponentFactory(DEFAULT_LANGUAGE); |
| } |
| |
| public MojoDescriptor(PluginDescriptor pd, org.apache.maven.api.plugin.descriptor.MojoDescriptor md) { |
| this(); |
| this.setPluginDescriptor(pd); |
| this.setGoal(md.getGoal()); |
| this.setExecuteGoal(md.getExecuteGoal()); |
| this.setExecuteLifecycle(md.getExecuteLifecycle()); |
| this.setExecutePhase(md.getExecutePhase()); |
| this.setDeprecated(md.getDeprecated()); |
| this.setLanguage(md.getLanguage()); |
| this.setAggregator(md.isAggregator()); |
| this.setDependencyCollectionRequired(md.getDependencyCollection()); |
| this.setDependencyResolutionRequired(md.getDependencyResolution()); |
| this.setComponentConfigurator(md.getConfigurator()); |
| this.setInheritedByDefault(md.isInheritedByDefault()); |
| this.setPhase(md.getPhase()); |
| this.setOnlineRequired(md.isOnlineRequired()); |
| this.setProjectRequired(md.isProjectRequired()); |
| this.setSince(md.getSince()); |
| this.setThreadSafe(true); |
| this.setV4Api(true); |
| this.setImplementation(md.getImplementation()); |
| try { |
| this.setParameters(md.getParameters().stream().map(Parameter::new).collect(Collectors.toList())); |
| } catch (DuplicateParameterException e) { |
| throw new IllegalArgumentException(e); |
| } |
| this.mojoDescriptorV4 = md; |
| } |
| // ---------------------------------------------------------------------- |
| // |
| // ---------------------------------------------------------------------- |
| |
| /** |
| * @return the language of this Mojo, i.e. <code>java</code> |
| */ |
| public String getLanguage() { |
| return getComponentFactory(); |
| } |
| |
| /** |
| * @param language the new language |
| */ |
| public void setLanguage(String language) { |
| setComponentFactory(language); |
| } |
| |
| /** |
| * @return Description with reason of a Mojo deprecation. |
| */ |
| public String getDeprecated() { |
| return deprecated; |
| } |
| |
| /** |
| * @param deprecated Description with reason of a Mojo deprecation. |
| */ |
| public void setDeprecated(String deprecated) { |
| this.deprecated = deprecated; |
| } |
| |
| /** |
| * @return the list of parameters copy. Any change to returned list is NOT reflected on this instance. To add |
| * parameters, use {@link #addParameter(Parameter)} method. |
| */ |
| public List<Parameter> getParameters() { |
| return new ArrayList<>(parameters); |
| } |
| |
| /** |
| * @param parameters the new list of parameters |
| * @throws DuplicateParameterException if any |
| */ |
| public void setParameters(List<Parameter> parameters) throws DuplicateParameterException { |
| this.parameters.clear(); |
| for (Parameter parameter : parameters) { |
| addParameter(parameter); |
| } |
| } |
| |
| /** |
| * @param parameter add a new parameter |
| * @throws DuplicateParameterException if any |
| */ |
| public void addParameter(Parameter parameter) throws DuplicateParameterException { |
| if (parameters.contains(parameter)) { |
| throw new DuplicateParameterException(parameter.getName() |
| + " has been declared multiple times in mojo with goal: " + getGoal() + " (implementation: " |
| + getImplementation() + ")"); |
| } |
| |
| parameters.add(parameter); |
| } |
| |
| /** |
| * @return the list parameters as a Map (keyed by {@link Parameter#getName()}) that is built from |
| * {@link #parameters} list on each call. In other words, the map returned is built on fly and is a copy. |
| * Any change to this map is NOT reflected on list and other way around! |
| */ |
| public Map<String, Parameter> getParameterMap() { |
| LinkedHashMap<String, Parameter> parameterMap = new LinkedHashMap<>(); |
| |
| for (Parameter pd : parameters) { |
| parameterMap.put(pd.getName(), pd); |
| } |
| |
| return parameterMap; |
| } |
| |
| // ---------------------------------------------------------------------- |
| // Dependency requirement |
| // ---------------------------------------------------------------------- |
| |
| /** |
| * @param requiresDependencyResolution the new required dependencies in a specified scope |
| */ |
| public void setDependencyResolutionRequired(String requiresDependencyResolution) { |
| this.dependencyResolutionRequired = requiresDependencyResolution; |
| } |
| |
| public String getDependencyResolutionRequired() { |
| return dependencyResolutionRequired; |
| } |
| |
| /** |
| * @return the required dependencies in a specified scope |
| * TODO the name is not intelligible |
| */ |
| @Deprecated |
| public String isDependencyResolutionRequired() { |
| return dependencyResolutionRequired; |
| } |
| |
| /** |
| * @since 3.0-alpha-3 |
| */ |
| public void setDependencyCollectionRequired(String requiresDependencyCollection) { |
| this.dependencyCollectionRequired = requiresDependencyCollection; |
| } |
| |
| /** |
| * Gets the scope of (transitive) dependencies that should be collected. Dependency collection refers to the process |
| * of calculating the complete dependency tree in terms of artifact coordinates. In contrast to dependency |
| * resolution, this does not include the download of the files for the dependency artifacts. It is meant for mojos |
| * that only want to analyze the set of transitive dependencies, in particular during early lifecycle phases where |
| * full dependency resolution might fail due to projects which haven't been built yet. |
| * |
| * @return The scope of (transitive) dependencies that should be collected or {@code null} if none. |
| * @since 3.0-alpha-3 |
| */ |
| public String getDependencyCollectionRequired() { |
| return dependencyCollectionRequired; |
| } |
| |
| // ---------------------------------------------------------------------- |
| // Project requirement |
| // ---------------------------------------------------------------------- |
| |
| /** |
| * @param requiresProject <code>true</code> if the Mojo needs a Maven project to be executed, <code>false</code> |
| * otherwise. |
| */ |
| public void setProjectRequired(boolean requiresProject) { |
| this.projectRequired = requiresProject; |
| } |
| |
| /** |
| * @return <code>true</code> if the Mojo needs a Maven project to be executed, <code>false</code> otherwise. |
| */ |
| public boolean isProjectRequired() { |
| return projectRequired; |
| } |
| |
| // ---------------------------------------------------------------------- |
| // Online vs. Offline requirement |
| // ---------------------------------------------------------------------- |
| |
| /** |
| * @param requiresOnline <code>true</code> if the Mojo is online, <code>false</code> otherwise. |
| */ |
| public void setOnlineRequired(boolean requiresOnline) { |
| this.onlineRequired = requiresOnline; |
| } |
| |
| /** |
| * @return <code>true</code> if the Mojo is online, <code>false</code> otherwise. |
| */ |
| // blech! this isn't even intelligible as a method name. provided for |
| // consistency... |
| public boolean isOnlineRequired() { |
| return onlineRequired; |
| } |
| |
| /** |
| * @return <code>true</code> if the Mojo is online, <code>false</code> otherwise. |
| */ |
| // more english-friendly method...keep the code clean! :) |
| public boolean requiresOnline() { |
| return onlineRequired; |
| } |
| |
| /** |
| * @return the bound phase name of the Mojo |
| */ |
| public String getPhase() { |
| return phase; |
| } |
| |
| /** |
| * @param phase the new bound phase name of the Mojo |
| */ |
| public void setPhase(String phase) { |
| this.phase = phase; |
| } |
| |
| /** |
| * @return the version when the Mojo was added to the API |
| */ |
| public String getSince() { |
| return since; |
| } |
| |
| /** |
| * @param since the new version when the Mojo was added to the API |
| */ |
| public void setSince(String since) { |
| this.since = since; |
| } |
| |
| /** |
| * @return The goal name of the Mojo |
| */ |
| public String getGoal() { |
| return goal; |
| } |
| |
| /** |
| * @param goal The new goal name of the Mojo |
| */ |
| public void setGoal(String goal) { |
| this.goal = goal; |
| } |
| |
| /** |
| * @return the invocation phase of the Mojo |
| */ |
| public String getExecutePhase() { |
| return executePhase; |
| } |
| |
| /** |
| * @param executePhase the new invocation phase of the Mojo |
| */ |
| public void setExecutePhase(String executePhase) { |
| this.executePhase = executePhase; |
| } |
| |
| /** |
| * @return <code>true</code> if the Mojo uses <code>always</code> for the <code>executionStrategy</code> |
| */ |
| public boolean alwaysExecute() { |
| return MULTI_PASS_EXEC_STRATEGY.equals(executionStrategy); |
| } |
| |
| /** |
| * @return the execution strategy |
| */ |
| public String getExecutionStrategy() { |
| return executionStrategy; |
| } |
| |
| /** |
| * @param executionStrategy the new execution strategy |
| */ |
| public void setExecutionStrategy(String executionStrategy) { |
| this.executionStrategy = executionStrategy; |
| } |
| |
| /** |
| * @return the mojo configuration |
| */ |
| public PlexusConfiguration getMojoConfiguration() { |
| if (mojoConfiguration == null) { |
| mojoConfiguration = new XmlPlexusConfiguration("configuration"); |
| } |
| return mojoConfiguration; |
| } |
| |
| /** |
| * @param mojoConfiguration a new mojo configuration |
| */ |
| public void setMojoConfiguration(PlexusConfiguration mojoConfiguration) { |
| this.mojoConfiguration = mojoConfiguration; |
| } |
| |
| /** {@inheritDoc} */ |
| public String getRole() { |
| return isV4Api() ? "org.apache.maven.api.plugin.Mojo" : Mojo.ROLE; |
| } |
| |
| /** {@inheritDoc} */ |
| public String getRoleHint() { |
| return getId(); |
| } |
| |
| /** |
| * @return the id of the mojo, based on the goal name |
| */ |
| public String getId() { |
| return getPluginDescriptor().getId() + ":" + getGoal(); |
| } |
| |
| /** |
| * @return the full goal name |
| * @see PluginDescriptor#getGoalPrefix() |
| * @see #getGoal() |
| */ |
| public String getFullGoalName() { |
| return getPluginDescriptor().getGoalPrefix() + ":" + getGoal(); |
| } |
| |
| /** {@inheritDoc} */ |
| public String getComponentType() { |
| return MAVEN_PLUGIN; |
| } |
| |
| /** |
| * @return the plugin descriptor |
| */ |
| public PluginDescriptor getPluginDescriptor() { |
| return pluginDescriptor; |
| } |
| |
| /** |
| * @param pluginDescriptor the new plugin descriptor |
| */ |
| public void setPluginDescriptor(PluginDescriptor pluginDescriptor) { |
| this.pluginDescriptor = pluginDescriptor; |
| } |
| |
| /** |
| * @return <code>true</code> if the Mojo is inherited, <code>false</code> otherwise. |
| */ |
| public boolean isInheritedByDefault() { |
| return inheritedByDefault; |
| } |
| |
| /** |
| * @param inheritedByDefault <code>true</code> if the Mojo is inherited, <code>false</code> otherwise. |
| */ |
| public void setInheritedByDefault(boolean inheritedByDefault) { |
| this.inheritedByDefault = inheritedByDefault; |
| } |
| |
| /** {@inheritDoc} */ |
| public boolean equals(Object object) { |
| if (this == object) { |
| return true; |
| } |
| |
| if (object instanceof MojoDescriptor) { |
| MojoDescriptor other = (MojoDescriptor) object; |
| |
| return Objects.equals(getPluginDescriptor(), other.getPluginDescriptor()) |
| && Objects.equals(getGoal(), other.getGoal()); |
| } |
| |
| return false; |
| } |
| |
| /** {@inheritDoc} */ |
| public int hashCode() { |
| return Objects.hash(getGoal(), getPluginDescriptor()); |
| } |
| |
| /** |
| * @return the invocation lifecycle of the Mojo |
| */ |
| public String getExecuteLifecycle() { |
| return executeLifecycle; |
| } |
| |
| /** |
| * @param executeLifecycle the new invocation lifecycle of the Mojo |
| */ |
| public void setExecuteLifecycle(String executeLifecycle) { |
| this.executeLifecycle = executeLifecycle; |
| } |
| |
| /** |
| * @param aggregator <code>true</code> if the Mojo uses the Maven project and its child modules, |
| * <code>false</code> otherwise. |
| */ |
| public void setAggregator(boolean aggregator) { |
| this.aggregator = aggregator; |
| } |
| |
| /** |
| * @return <code>true</code> if the Mojo uses the Maven project and its child modules, |
| * <code>false</code> otherwise. |
| */ |
| public boolean isAggregator() { |
| return aggregator; |
| } |
| |
| /** |
| * @return <code>true</code> if the Mojo cannot be invoked directly, <code>false</code> otherwise. |
| */ |
| public boolean isDirectInvocationOnly() { |
| return directInvocationOnly; |
| } |
| |
| /** |
| * @param directInvocationOnly <code>true</code> if the Mojo cannot be invoked directly, |
| * <code>false</code> otherwise. |
| */ |
| public void setDirectInvocationOnly(boolean directInvocationOnly) { |
| this.directInvocationOnly = directInvocationOnly; |
| } |
| |
| /** |
| * @return <code>true</code> if the Mojo needs reports to run, <code>false</code> otherwise. |
| */ |
| public boolean isRequiresReports() { |
| return requiresReports; |
| } |
| |
| /** |
| * @param requiresReports <code>true</code> if the Mojo needs reports to run, <code>false</code> otherwise. |
| */ |
| public void setRequiresReports(boolean requiresReports) { |
| this.requiresReports = requiresReports; |
| } |
| |
| /** |
| * @param executeGoal the new invocation goal of the Mojo |
| */ |
| public void setExecuteGoal(String executeGoal) { |
| this.executeGoal = executeGoal; |
| } |
| |
| /** |
| * @return the invocation goal of the Mojo |
| */ |
| public String getExecuteGoal() { |
| return executeGoal; |
| } |
| |
| /** |
| * @return True if the <code>Mojo</code> is thread-safe and can be run safely in parallel |
| * @since 3.0-beta-2 |
| */ |
| public boolean isThreadSafe() { |
| return threadSafe; |
| } |
| |
| /** |
| * @param threadSafe indicates that the mojo is thread-safe and can be run safely in parallel |
| * @since 3.0-beta-2 |
| */ |
| public void setThreadSafe(boolean threadSafe) { |
| this.threadSafe = threadSafe; |
| } |
| |
| /** |
| * @return {@code true} if this mojo forks either a goal or the lifecycle, {@code false} otherwise. |
| */ |
| public boolean isForking() { |
| return (getExecuteGoal() != null && getExecuteGoal().length() > 0) |
| || (getExecutePhase() != null && getExecutePhase().length() > 0); |
| } |
| |
| public boolean isV4Api() { |
| return v4Api; |
| } |
| |
| public void setV4Api(boolean v4Api) { |
| this.v4Api = v4Api; |
| } |
| |
| /** |
| * Creates a shallow copy of this mojo descriptor. |
| */ |
| @Override |
| public MojoDescriptor clone() { |
| try { |
| return (MojoDescriptor) super.clone(); |
| } catch (CloneNotSupportedException e) { |
| throw new UnsupportedOperationException(e); |
| } |
| } |
| |
| private volatile org.apache.maven.api.plugin.descriptor.MojoDescriptor mojoDescriptorV4; |
| |
| public org.apache.maven.api.plugin.descriptor.MojoDescriptor getMojoDescriptorV4() { |
| if (mojoDescriptorV4 == null) { |
| synchronized (this) { |
| if (mojoDescriptorV4 == null) { |
| mojoDescriptorV4 = org.apache.maven.api.plugin.descriptor.MojoDescriptor.newBuilder() |
| .goal(goal) |
| .description(getDescription()) |
| .implementation(getImplementation()) |
| .language(getLanguage()) |
| .phase(phase) |
| .executeGoal(executeGoal) |
| .executeLifecycle(executeLifecycle) |
| .executePhase(executePhase) |
| .aggregator(aggregator) |
| .dependencyResolution(dependencyResolutionRequired) |
| .dependencyCollection(dependencyCollectionRequired) |
| .projectRequired(projectRequired) |
| .onlineRequired(onlineRequired) |
| .inheritedByDefault(inheritedByDefault) |
| .since(since) |
| .deprecated(deprecated) |
| .configurator(getComponentConfigurator()) |
| .parameters(getParameters().stream() |
| .filter(p -> p.getRequirement() == null) |
| .map(Parameter::getParameterV4) |
| .collect(Collectors.toList())) |
| .id(getId()) |
| .fullGoalName(getFullGoalName()) |
| .build(); |
| } |
| } |
| } |
| return mojoDescriptorV4; |
| } |
| } |