org.codehaus.cargo.maven2.configuration.Deployable 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.configuration;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.tools.ant.BuildException;
import org.codehaus.cargo.container.deployable.DeployableType;
import org.codehaus.cargo.container.deployable.EAR;
import org.codehaus.cargo.container.deployable.WAR;
import org.codehaus.cargo.generic.deployable.DefaultDeployableFactory;
import org.codehaus.cargo.generic.deployable.DeployableFactory;
import org.codehaus.cargo.maven2.util.CargoProject;
/**
* Holds configuration data for the <deployable>
tag used to configure the plugin
* in the pom.xml
file.
* TODO: Find a way to remove code duplication with Ant's DeployableElement
*/
public class Deployable extends AbstractDependency
{
/**
* Constant for Maven2 project type ejb
.
*/
private static final String EJB = "ejb";
/**
* Constant for Maven2 project type bundle
.
*/
private static final String BUNDLE = "bundle";
/**
* Constant for Maven2 project type uberwar
.
*/
private static final String UBERWAR = "uberwar";
/**
* Constant for Maven2 project type starting with jboss-
.
* JBoss needs special checks, see https://codehaus-cargo.atlassian.net/browse/CARGO-710
*/
private static final String JBOSS = "jboss-";
/**
* Length of {@link Deployable#JBOSS}
*/
private static final int JBOSS_STRIP = Deployable.JBOSS.length();
/**
* Ping URL.
*/
private URL pingURL;
/**
* Ping URL path.
*/
private String pingUrlPath;
/**
* Ping timeout.
*/
private Long pingTimeout;
/**
* Implementation.
*/
private String implementation;
/**
* Deployable properties.
*/
private Map properties;
/**
* @return Deployable properties.
*/
public Map getProperties()
{
return this.properties;
}
/**
* @param properties Deployable properties.
*/
public void setProperties(Map properties)
{
this.properties = properties;
}
/**
* @return Ping URL.
*/
public URL getPingURL()
{
return this.pingURL;
}
/**
* @return Ping URL path.
*/
public String getPingUrlPath()
{
return this.pingUrlPath;
}
/**
* @return Ping timeout.
*/
public Long getPingTimeout()
{
return this.pingTimeout;
}
/**
* @param implementation Implementation.
*/
public void setImplementation(String implementation)
{
this.implementation = implementation;
}
/**
* @return Implementation.
*/
public String getImplementation()
{
return this.implementation;
}
/**
* Create a deployable.
* @param containerId Container identifier.
* @param project Cargo project.
* @return Deployable.
* @throws MojoExecutionException If location computation or deployable instanciation fails.
*/
public org.codehaus.cargo.container.deployable.Deployable createDeployable(String containerId,
CargoProject project) throws MojoExecutionException
{
project.getLog().debug("Initial deployable values: groupId = [" + getGroupId()
+ "], artifactId = [" + getArtifactId() + "], type = [" + getType()
+ "], location = [" + getLocation() + "]");
// If no groupId is specified use the project's groupId
if (getGroupId() == null)
{
setGroupId(project.getGroupId());
}
// If no type is specified use the project's packaging
if (getType() == null)
{
setType(project.getPackaging());
}
// If no artifactId is specified use the project's artifactId
if (getArtifactId() == null)
{
setArtifactId(project.getArtifactId());
}
// If no location is specified, guess the location
if (getLocation() == null)
{
setLocation(computeLocation(project));
}
project.getLog().debug(
"Computed deployable values: groupId = [" + getGroupId()
+ "], artifactId = [" + getArtifactId() + "], classifier = [" + getClassifier()
+ "], type = [" + getType()
+ "], location = [" + getLocation() + "]");
DeployableFactory factory = new DefaultDeployableFactory();
// If a custom implementation class is defined register it against the deployable factory.
if (getImplementation() != null)
{
try
{
Class deployableClass = Class.forName(getImplementation(), true,
this.getClass().getClassLoader());
factory.registerDeployable(containerId, DeployableType.toType(getType()),
deployableClass);
}
catch (ClassNotFoundException cnfe)
{
throw new MojoExecutionException("Custom deployable implementation ["
+ getImplementation() + "] cannot be loaded", cnfe);
}
}
org.codehaus.cargo.container.deployable.Deployable deployable =
factory.createDeployable(containerId, getLocation(), DeployableType.toType(getType()));
// Set user-defined properties on the created deployable.
setPropertiesOnDeployable(deployable, project);
String name = null;
String context = null;
if (getProperties() != null)
{
name = getProperties().get("name");
context = getProperties().get("context");
}
if (deployable instanceof EAR && name == null)
{
EAR ear = (EAR) deployable;
ear.setName(getArtifactId());
}
if (deployable instanceof WAR && context == null)
{
WAR war = (WAR) deployable;
if (getGroupId().equals(project.getGroupId())
&& getArtifactId().equals(project.getArtifactId()))
{
// CARGO-1279: Honor the finalName if it was set manually
context = project.getFinalName();
if (context == null || context.startsWith(getArtifactId() + '-'))
{
context = getArtifactId();
}
}
else
{
context = getArtifactId();
}
war.setContext(context);
}
return deployable;
}
/**
* Set user-defined properties on the created deployable.
* @param deployable the deployable on which to set the properties
* @param project Cargo project.
*/
protected void setPropertiesOnDeployable(
org.codehaus.cargo.container.deployable.Deployable deployable, CargoProject project)
{
if (getProperties() != null)
{
for (Map.Entry property : getProperties().entrySet())
{
String propertyName = property.getKey();
project.getLog().debug("Setting deployable property [" + propertyName + "]:["
+ getProperties().get(propertyName) + "] for [" + getLocation() + "]");
// Maven2 doesn't like empty elements and will set them to Null. Thus we
// need to modify that behavior and change them to an empty string. For example
// this allows users to pass an empty context to mean the root context.
String propertyValue = property.getValue();
if (propertyValue == null)
{
propertyValue = "";
}
try
{
callMethodForProperty(deployable, propertyName, propertyValue, project);
}
catch (Exception e)
{
throw new BuildException("Invalid property [" + propertyName
+ "] for deployable type [" + deployable.getType() + "]", e);
}
}
}
}
/**
* Compute the location of the current deployable.
* @param project Cargo project.
* @return Location of current deployable.
* @throws MojoExecutionException If location cannot be found.
*/
protected String computeLocation(CargoProject project) throws MojoExecutionException
{
String location;
// If the groupId and artifactId match those of the project then we consider that the
// deployable is the artifact generated by the project. We also check that the defined
// Cargo type matches Maven's defined packaging. If it doesn't we look for the deployable
// in the project's dependency list.
if (project.getGroupId().equals(getGroupId())
&& project.getArtifactId().equals(getArtifactId())
&& isTypeCompatible(project))
{
String type = this.getType();
this.setType(project.getPackaging());
try
{
// Let's look in the project's dependencies and find a match.
location = findArtifactLocation(project.getArtifacts(), project.getLog());
}
catch (MojoExecutionException e)
{
String classifier = getClassifier();
// Compute default location.
if (classifier == null)
{
location = new File(project.getBuildDirectory(), project.getFinalName() + "."
+ computeExtension(project.getPackaging())).getPath();
}
else
{
location = new File(project.getBuildDirectory(), project.getFinalName() + "-"
+ classifier + "." + computeExtension(project.getPackaging())).getPath();
}
}
finally
{
this.setType(type);
}
}
else
{
// Display a warning if the groupId and artifactId are the same as the project's but
// the type is different.
if (project.getGroupId().equals(getGroupId())
&& project.getArtifactId().equals(getArtifactId()))
{
project
.getLog()
.warn("The defined deployable has the same groupId and artifactId "
+ "as your project's main artifact but the type is different. You've "
+ "defined a [" + getType() + "] type whereas the project's packaging is ["
+ project.getPackaging() + "]. This is possibly an error and as a "
+ "consequence the plugin will try to find this deployable in the "
+ "project's dependencies.");
}
// Let's look in the project's dependencies and find a match.
location = findArtifactLocation(project.getArtifacts(), project.getLog());
}
return location;
}
/**
* Checks if deployable type is compatible with the project's packaging.
* @param project Cargo project.
* @return true
if the deployable type is compatible with the project's packaging.
*/
protected boolean isTypeCompatible(CargoProject project)
{
boolean isMatching = false;
if (getType().equalsIgnoreCase(project.getPackaging())
|| getType().equalsIgnoreCase("file"))
{
isMatching = true;
}
else if (getType().equalsIgnoreCase("war")
&& project.getPackaging().equalsIgnoreCase(Deployable.UBERWAR))
{
isMatching = true;
}
else if (project.getPackaging().startsWith(Deployable.JBOSS)
&& getType().equalsIgnoreCase(
project.getPackaging().substring(Deployable.JBOSS_STRIP)))
{
isMatching = true;
}
return isMatching;
}
/**
* Compute the extension for a given Maven2 packaging.
* @param packaging Maven2 project packaging (ex: ejb, ear, rar, war, etc)
* @return Artifact extension matching the packaging
*/
protected String computeExtension(String packaging)
{
String extension;
if (packaging.equalsIgnoreCase(Deployable.EJB)
|| packaging.equalsIgnoreCase(Deployable.BUNDLE))
{
extension = "jar";
}
else if (packaging.equalsIgnoreCase(Deployable.UBERWAR))
{
extension = "war";
}
else if (packaging.startsWith(Deployable.JBOSS))
{
extension = packaging.substring(Deployable.JBOSS_STRIP);
}
else
{
extension = packaging;
}
return extension;
}
/**
* Call setter methods corresponding to deployable properties.
* @param deployable Deployable on which to call the setter method corresponding to the
* specified property.
* @param name Property name.
* @param value Property value.
* @param project Cargo project.
* @throws Exception if anything goes wrong.
*/
private void callMethodForProperty(
org.codehaus.cargo.container.deployable.Deployable deployable, String name, String value,
CargoProject project) throws Exception
{
String setterMethodName = getSetterMethodName(name);
Method method;
Object argument;
try
{
method = deployable.getClass().getMethod(setterMethodName, new Class[] {String.class});
argument = value;
}
catch (NoSuchMethodException e)
{
// If we reach this line, it means there is no String setter for the given property
// name with a String argument. Check if there is a setter with String[] argument; if
// there is one split the value at each line and call the setter.
method = deployable.getClass().getMethod(setterMethodName,
new Class[] {String[].class});
List valueList = new ArrayList();
StringTokenizer commaSeparatedValue = new StringTokenizer(value, ",");
while (commaSeparatedValue.hasMoreTokens())
{
String commaSeparatedLine = commaSeparatedValue.nextToken().trim();
if (!commaSeparatedLine.isEmpty())
{
valueList.add(commaSeparatedLine);
}
}
String[] valueArray = new String[valueList.size()];
valueArray = valueList.toArray(valueArray);
argument = valueArray;
}
project.getLog().debug("Invoking setter method " + method + " for deployable "
+ deployable + " with argument " + argument);
method.invoke(deployable, new Object[] {argument});
}
/**
* Transform a property into a method name by transforming the first letter of the property name
* to uppercase.
* @param propertyName Property name to transform into a setter method
* @return Setter method's name
*/
protected String getSetterMethodName(String propertyName)
{
return "set" + propertyName.substring(0, 1).toUpperCase(Locale.ENGLISH)
+ propertyName.substring(1);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy