org.codehaus.cargo.maven2.AbstractCargoMojo Maven / Gradle / Ivy
/*
* ========================================================================
*
* Codehaus CARGO, copyright 2004-2011 Vincent Massol, 2012-2020 Ali Tokmen.
*
* Licensed 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.codehaus.cargo.maven2;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.Security;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.settings.Proxy;
import org.apache.maven.settings.Server;
import org.apache.maven.settings.Settings;
import org.codehaus.cargo.container.ContainerType;
import org.codehaus.cargo.container.LocalContainer;
import org.codehaus.cargo.container.RemoteContainer;
import org.codehaus.cargo.container.configuration.ConfigurationType;
import org.codehaus.cargo.container.configuration.LocalConfiguration;
import org.codehaus.cargo.container.configuration.RuntimeConfiguration;
import org.codehaus.cargo.container.deployer.DeployableMonitor;
import org.codehaus.cargo.container.internal.util.ResourceUtils;
import org.codehaus.cargo.container.spi.deployer.DeployerWatchdog;
import org.codehaus.cargo.maven2.configuration.ArtifactInstaller;
import org.codehaus.cargo.maven2.configuration.Configuration;
import org.codehaus.cargo.maven2.configuration.Container;
import org.codehaus.cargo.maven2.configuration.Daemon;
import org.codehaus.cargo.maven2.configuration.Deployable;
import org.codehaus.cargo.maven2.configuration.Deployer;
import org.codehaus.cargo.maven2.configuration.ZipUrlInstaller;
import org.codehaus.cargo.maven2.deployer.DefaultDeployableMonitorFactory;
import org.codehaus.cargo.maven2.deployer.DeployableMonitorFactory;
import org.codehaus.cargo.maven2.log.MavenLogger;
import org.codehaus.cargo.maven2.util.CargoProject;
import org.codehaus.cargo.maven2.util.EmbeddedContainerArtifactResolver;
import org.codehaus.cargo.util.DefaultFileHandler;
import org.codehaus.cargo.util.FileHandler;
import org.codehaus.cargo.util.log.FileLogger;
import org.codehaus.cargo.util.log.LogLevel;
import org.codehaus.cargo.util.log.Logger;
import org.codehaus.plexus.util.xml.Xpp3Dom;
/**
* Common code used by Cargo MOJOs requiring <container>
and
* <configuration>
elements and supporting the notion of Auto-deployable.
*/
public abstract class AbstractCargoMojo extends AbstractCommonMojo
{
/**
* The key under which the container instance is stored in the plugin context. We store it so
* that it's possible to get back the same container instance even if this mojo is called in a
* different Maven execution context. This is required for stopping embedded containers for
* example as we need to use the same instance that was started in order to stop them.
*/
public static final String CONTEXT_KEY_CONTAINER =
AbstractCargoMojo.class.getName() + "-Container";
/**
* The key suffix under which the classloader of the container instance is stored
* in the plugin context. We store it so that it's possible to get back the same classloader
* even if this mojo is called in a different Maven execution context.
* This is required for starting and stopping multiple containers as each container
* initialization requires different classloader.
*/
public static final String CONTEXT_KEY_CLASSLOADER = "-classloader";
/**
* File utility class.
*/
private FileHandler fileHandler = new DefaultFileHandler();
/**
* Configures a Cargo {@link org.codehaus.cargo.container.configuration.Configuration}. See the
* Cargo
* Maven 2 / Maven 3 plugin reference guide for more details.
*
* @parameter
* @see #getConfigurationElement()
*/
private Configuration configuration;
/**
* Configures a Cargo {@link org.codehaus.cargo.container.Container}. See the Cargo
* Maven 2 / Maven 3 plugin reference guide for more details.
*
* @parameter
*/
private Container container;
/**
* Daemon configuration.
*
* @parameter
*/
private Daemon daemon;
/**
* Configures a Cargo {@link org.codehaus.cargo.container.deployer.Deployer}. See the Cargo
* Maven 2 / Maven 3 plugin reference guide for more details.
*
* @parameter
* @see #getDeployerElement()
*/
private Deployer deployer;
/**
* List of {@link org.codehaus.cargo.maven2.configuration.Deployable}. See the Cargo
* Maven 2 / Maven 3 plugin reference guide for more details.
*
* @parameter
* @see #getDeployablesElement()
*/
private Deployable[] deployables;
/**
* The metadata source.
*
* @component
*/
private ArtifactMetadataSource metadataSource;
/**
* Maven artifact resolver, used to dynamically resolve JARs for the containers and also to
* resolve the JARs for the embedded container's classpaths.
*
* @component
*/
private ArtifactResolver artifactResolver;
/**
* The local Maven repository. This is used by the artifact resolver to download resolved
* artifacts and put them in the local repository so that they won't have to be fetched again
* next time the plugin is executed.
*
* @parameter property="localRepository"
* @required
* @readonly
*/
private ArtifactRepository localRepository;
/**
* The remote Maven repositories used by the artifact resolver to look for artifacts.
*
* @parameter property="project.remoteArtifactRepositories"
* @required
* @readonly
*/
private List repositories;
/**
* Set this to 'true' to bypass cargo execution.
*
* @parameter property="cargo.maven.skip" default-value="false"
* @since 1.0.3
*/
private boolean skip;
/**
* The artifact factory is used to create valid Maven {@link org.apache.maven.artifact.Artifact}
* objects. This is used to pass Maven artifacts to the artifact resolver so that it can
* download the required JARs to put in the embedded container's classpaths.
*
* @component
*/
private ArtifactFactory artifactFactory;
/**
* @see org.codehaus.cargo.maven2.util.CargoProject
*/
private CargoProject cargoProject;
/**
* Maven settings, injected automatically.
*
* @parameter property="settings"
* @required
* @readonly
*/
private Settings settings;
/**
* Cargo plugin version.
*
* @parameter property="plugin.version"
* @required
* @readonly
*/
private String pluginVersion;
/**
* Should the mojo ignore failures if something fails
*
* @parameter property="cargo.ignore.failures" default-value="false"
*/
private boolean ignoreFailures = false;
/**
* Calculates the container artifact ID for a given container ID. Note that all containers
* identifier are in the form containerArtifactId + the version number + x
; for
* example jboss42x
is from container artifact ID
* cargo-core-container-jboss
.
* @param containerId Container ID, for example jboss42x
.
* @return Container artifact ID, for example cargo-core-container-jboss
.
*/
public static String calculateContainerArtifactId(String containerId)
{
return "cargo-core-container-" + containerId.replaceAll("\\d+x", "");
}
/**
* @return the Cargo file utility class
*/
protected FileHandler getFileHandler()
{
return this.fileHandler;
}
/**
* @param fileHandler the Cargo file utility class to use. This method is useful for unit
* testing with Mock objects as it can be passed a test file handler that doesn't perform any
* real file action.
*/
protected void setFileHandler(FileHandler fileHandler)
{
this.fileHandler = fileHandler;
}
/**
* @return the user configuration of a Cargo
* {@link org.codehaus.cargo.container.deployer.Deployer}. See the Cargo
* Maven 2 / Maven 3 plugin reference guide and
* {@link org.codehaus.cargo.maven2.configuration.Deployer} for more details.
*/
protected Deployer getDeployerElement()
{
return this.deployer;
}
/**
* @param deployerElement the {@link org.codehaus.cargo.container.deployer.Deployer}
* configuration defined by the user
* @see #getDeployerElement()
*/
protected void setDeployerElement(Deployer deployerElement)
{
this.deployer = deployerElement;
}
/**
* @return The daemon configuration
*/
protected Daemon getDaemon()
{
if (this.daemon == null)
{
this.daemon = new Daemon();
}
return this.daemon;
}
/**
* @return the user configuration of the list of
* {@link org.codehaus.cargo.maven2.configuration.Deployable}. See the Cargo
* Maven 2 / Maven 3 plugin reference guide for more details.
*/
protected Deployable[] getDeployablesElement()
{
return this.deployables;
}
/**
* @param deployablesElement the list of
* {@link org.codehaus.cargo.maven2.configuration.Deployable}. See the Cargo
* Maven 2 / Maven 3 plugin reference guide for more details.
* @see #getDeployablesElement()
*/
protected void setDeployablesElement(Deployable[] deployablesElement)
{
this.deployables = deployablesElement;
}
/**
* @return the user configuration of a Cargo
* {@link org.codehaus.cargo.container.configuration.Configuration}. See the Cargo
* Maven 2 / Maven 3 plugin reference guide and
* {@link org.codehaus.cargo.maven2.configuration.Configuration} for more details.
*/
protected Configuration getConfigurationElement()
{
return this.configuration;
}
/**
* @param configurationElement the
* {@link org.codehaus.cargo.container.configuration.Configuration} configuration defined by the
* user
* @see #getConfigurationElement()
*/
protected void setConfigurationElement(Configuration configurationElement)
{
this.configuration = configurationElement;
}
/**
* @return the user configuration of a Cargo {@link org.codehaus.cargo.container.Container}.
* See the
* Cargo Maven 2 / Maven 3 plugin reference guide and
* {@link org.codehaus.cargo.maven2.configuration.Container} for more details.
*/
protected Container getContainerElement()
{
return this.container;
}
/**
* @param containerElement the {@link org.codehaus.cargo.container.Container} configuration
* defined by the user
* @see #getContainerElement()
*/
protected void setContainerElement(Container containerElement)
{
this.container = containerElement;
}
/**
* @param cargoProject Cargo project
*/
protected void setCargoProject(CargoProject cargoProject)
{
this.cargoProject = cargoProject;
}
/**
* @return Cargo project
*/
protected CargoProject getCargoProject()
{
return this.cargoProject;
}
/**
* @return the ignoreFailures
*/
public boolean isIgnoreFailures()
{
return ignoreFailures;
}
/**
* @param ignoreFailures
* the ignoreFailures to set
*/
public void setIgnoreFailures(boolean ignoreFailures)
{
this.ignoreFailures = ignoreFailures;
}
/**
* {@inheritDoc}
*
*
* Note: This method is final so that extending classes cannot extend it. Instead they should
* implement the {@link #doExecute()} method.
*
*/
@Override
public final void execute() throws MojoExecutionException
{
if (this.skip)
{
getLog().info("Skipping cargo execution");
return;
}
if (this.cargoProject == null)
{
this.cargoProject = new CargoProject(getProject(), getLog());
}
// CARGO-1042: Clear proxy settings before starting execution
// CARGO-1119 and CARGO-1121: Use proxy settings from the Maven2 proxy settings
final Map previousProperties = new HashMap(10);
previousProperties.put("http.proxyHost", System.clearProperty("http.proxyHost"));
previousProperties.put("http.proxyPort", System.clearProperty("http.proxyPort"));
previousProperties.put("https.proxyHost", System.clearProperty("https.proxyHost"));
previousProperties.put("https.proxyPort", System.clearProperty("https.proxyPort"));
previousProperties.put("http.proxyUser", System.clearProperty("http.proxyUser"));
previousProperties.put("http.proxyPassword", System.clearProperty("http.proxyPassword"));
previousProperties.put("https.proxyUser", System.clearProperty("https.proxyUser"));
previousProperties.put("https.proxyPassword", System.clearProperty("https.proxyPassword"));
previousProperties.put("http.nonProxyHosts", System.clearProperty("http.nonProxyHosts"));
previousProperties.put("https.nonProxyHosts", System.clearProperty("https.nonProxyHosts"));
try
{
Proxy proxy = null;
if (settings != null)
{
proxy = settings.getActiveProxy();
}
if (proxy != null)
{
if (proxy.getHost() != null)
{
System.setProperty("http.proxyHost", proxy.getHost());
System.setProperty("https.proxyHost", proxy.getHost());
System.setProperty("http.proxyPort", Integer.toString(proxy.getPort()));
System.setProperty("https.proxyPort", Integer.toString(proxy.getPort()));
}
if (proxy.getUsername() != null && proxy.getPassword() != null)
{
System.setProperty("http.proxyUser", proxy.getUsername());
System.setProperty("https.proxyUser", proxy.getUsername());
System.setProperty("http.proxyPassword", proxy.getPassword());
System.setProperty("https.proxyPassword", proxy.getPassword());
}
if (proxy.getNonProxyHosts() != null)
{
System.setProperty("http.nonProxyHosts", proxy.getNonProxyHosts());
System.setProperty("https.nonProxyHosts", proxy.getNonProxyHosts());
}
}
try
{
doExecute();
}
catch (MojoExecutionException e)
{
if (ignoreFailures)
{
getLog().error("Ignoring failures during execution", e);
}
else
{
throw e;
}
}
}
finally
{
for (Map.Entry previousProperty : previousProperties.entrySet())
{
if (previousProperty.getValue() != null)
{
System.setProperty(previousProperty.getKey(), previousProperty.getValue());
}
else
{
System.clearProperty(previousProperty.getKey());
}
}
}
}
/**
* Executes the plugin.
*
*
* This method must be implemented by all Mojos extending this class. The reason for this
* pattern is because we want the {@link #execute()} method to always be called so that
* necessary plugin initialization can be performed. Without this pattern Mojos extending this
* class could "forget" to call super.execute()
thus leading to unpredictible
* results.
*
*
* @throws MojoExecutionException in case of error
*/
protected abstract void doExecute() throws MojoExecutionException;
/**
* Creates a {@link org.codehaus.cargo.container.configuration.Configuration} instance. If the
* user has not specified a configuration element in the POM file then automatically create a
* standalone configuration if the container's type is local or otherwise create a runtime
* configuration.
*
* @return a valid {@link org.codehaus.cargo.container.configuration.Configuration} instance
* @throws MojoExecutionException in case of error
*/
protected org.codehaus.cargo.container.configuration.Configuration createConfiguration()
throws MojoExecutionException
{
org.codehaus.cargo.container.configuration.Configuration configuration;
// If no configuration element has been specified create one with default values.
if (getConfigurationElement() == null)
{
Configuration configurationElement = new Configuration();
if (getContainerElement().getType().isLocal())
{
File home = new File(getCargoProject().getBuildDirectory(), "cargo/configurations/"
+ getContainerElement().getContainerId());
configurationElement.setType(ConfigurationType.STANDALONE);
configurationElement.setHome(home.getAbsolutePath());
}
else
{
configurationElement.setType(ConfigurationType.RUNTIME);
}
setConfigurationElement(configurationElement);
}
else
{
if (getConfigurationElement().getHome() != null && !getCargoProject().isDaemonRun())
{
getConfigurationElement().setHome(calculateAbsoluteDirectory("configuration home",
getConfigurationElement().getHome()));
}
}
configuration = getConfigurationElement().createConfiguration(
getContainerElement().getContainerId(), getContainerElement().getType(),
getDeployablesElement(), getCargoProject());
// Find the container context key or cargo.server.settings for the current configuration.
// When found, iterate in the list of servers in Maven's settings.xml file in order to find
// out which server id corresponds to that identifier, and copy all non-set settings.
//
// This feature helps people out in centralising their configurations.
String serverId = configuration.getPropertyValue("cargo.server.settings");
if (serverId != null && !serverId.isEmpty())
{
getLog().debug("Found cargo.server.settings: " + serverId);
}
else if (getContainerElement() != null && getContainerElement().getContextKey() != null
&& !getContainerElement().getContextKey().isEmpty())
{
serverId = getContainerElement().getContextKey();
getLog().debug("Found container context key: " + serverId);
}
if (serverId != null && !serverId.isEmpty())
{
for (Object serverObject : settings.getServers())
{
Server server = (Server) serverObject;
if (serverId.equals(server.getId()))
{
getLog().info(
"The Maven settings.xml file contains a reference for the server with "
+ "identifier [" + serverId + "], injecting configuration properties");
Xpp3Dom[] globalConfigurationOptions = ((Xpp3Dom) server.getConfiguration())
.getChildren();
for (Xpp3Dom option : globalConfigurationOptions)
{
if (getConfigurationElement().getSetProperties() == null
|| !getConfigurationElement().getSetProperties().contains(
option.getName()))
{
configuration.setProperty(option.getName(), option.getValue());
if (option.getName().contains("password"))
{
getLog().debug(
"\tInjected password property: " + option.getName() + "= ***");
}
else
{
getLog().debug(
"\tInjected property: " + option.getName() + " = "
+ option.getValue());
}
}
else
{
getLog().debug(
"\tProperty " + option.getName()
+ " already set in the Maven artifact, skipping");
}
}
break;
}
}
}
return configuration;
}
/**
* @return a {@link org.codehaus.cargo.container.Container} instance if no container object was
* stored in the Maven Plugin Context or returns the saved instance otherwise. If a new
* container instance is created it's also saved in the Maven Plugin Context for later
* retrieval.
* @throws MojoExecutionException in case of error
*/
protected org.codehaus.cargo.container.Container createContainer()
throws MojoExecutionException
{
org.codehaus.cargo.container.Container container = null;
// Try to find the container in the Maven Plugin Context first.
Map
© 2015 - 2024 Weber Informatics LLC | Privacy Policy