package org.sakaiproject.maven.plugin.component;
/*
* 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.
*/
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.resolver.AbstractArtifactResolutionException;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.StringUtils;
/**
* Deploy artifacts to a copy of Tomcat
*/
@Mojo(name = "deploy", requiresDependencyResolution = ResolutionScope.RUNTIME, threadSafe = true)
public class ComponentDeployMojo extends AbstractComponentMojo {
/**
* The directory where the webapp is built.
*/
@Parameter(defaultValue = "${maven.tomcat.home}/components/${project.build.finalName}", required = true)
private File deployDirectory;
/**
* A map to define the destination where items are unpacked.
*/
@Parameter(defaultValue = "${sakai.app.server}")
private String appServer = null;
/**
* The ID of the artifact to use when deploying.
*/
@Parameter(defaultValue = "${project.artifactId}", required = true)
private String deployId = null;
/**
* Should we cleanup old versions when an artifact is deployed containing a version.
*/
@Parameter(defaultValue = "${sakai.cleanup}")
private boolean cleanup = false;
private Properties locationMap;
private static Properties defaultLocationMap;
/**
* Skip deployment
*/
@Parameter(property = "skip")
private boolean skip = false;
static {
defaultLocationMap = new Properties();
defaultLocationMap.setProperty("components", "components/");
defaultLocationMap.setProperty("webapps", "webapps/");
defaultLocationMap.setProperty("shared/lib", "lib/");
defaultLocationMap.setProperty("server/lib", "lib/");
defaultLocationMap.setProperty("common/lib", "lib/");
defaultLocationMap.setProperty("configuration", "/");
defaultLocationMap.setProperty("endorsed", "endorsed/");
}
private boolean explodeWars = false;
public File getDeployDirectory() {
return deployDirectory;
}
public void setDeployDirectory(File deployDirectory) {
this.deployDirectory = deployDirectory;
}
public String getAppServer()
{
return appServer;
}
public void setAppServer(String appServer)
{
this.appServer = appServer;
}
public String getDeployId()
{
return deployId;
}
public void setDeployId(String deployId)
{
this.deployId = deployId;
}
public boolean isCleanup() {
return cleanup;
}
public void setCleanup(boolean cleanup) {
this.cleanup = cleanup;
}
public boolean isSkip() {
return skip;
}
public void setSkip(boolean skip) {
this.skip = skip;
}
public boolean isExplodeWars() {
return explodeWars;
}
public void setExplodeWars(boolean explodeWars) {
this.explodeWars = explodeWars;
}
public void execute() throws MojoExecutionException, MojoFailureException {
if ( skip ) {
getLog().info( "Skipping artifact deployment " +
project.getGroupId() + ":" +
project.getArtifactId() + ":" +
project.getPackaging());
} else {
deployToContainer();
}
}
public void deployToContainer() throws MojoExecutionException,
MojoFailureException
{
try {
Set artifacts = project.getDependencyArtifacts();
// iterate through the this to extract dependencies and deploy
String packaging = project.getPackaging();
File deployDir = getDeployDirectory();
if (deployDir == null) {
throw new MojoFailureException(
"deployDirectory has not been set");
}
if ("sakai-component".equals(packaging)) {
// UseCase: Sakai component in a pom
// deploy to component and unpack as a
getLog().info(
"Deploying " + project.getGroupId() + ":"
+ project.getArtifactId() + ":"
+ project.getPackaging()
+ " as an unpacked component");
File destination = new File(deployDir, getDeploySubDir("components"));
String fileName = project.getArtifactId();
File destinationDir = new File(destination, fileName);
Artifact artifact = project.getArtifact();
if (artifact == null) {
getLog().error(
"No Artifact found in project " + getProjectId());
throw new MojoFailureException(
"No Artifact found in project");
}
File artifactFile = artifact.getFile();
if (artifactFile == null) {
artifactResolver.resolve(artifact, remoteRepositories,
artifactRepository);
artifactFile = artifact.getFile();
}
if (artifactFile == null) {
getLog().error(
"Artifact File is null for " + getProjectId());
throw new MojoFailureException("Artifact File is null ");
}
getLog().info(
"Unpacking " + artifactFile + " to " + destinationDir);
deleteAll(destinationDir);
destinationDir.mkdirs();
unpack(artifactFile, destinationDir, "war", false);
}
else if ("sakai-configuration".equals(packaging)) {
// UseCase: Sakai configuration in a pom
// deploy to component and unpack as a
getLog().info(
"Deploying " + project.getGroupId() + ":"
+ project.getArtifactId() + ":"
+ project.getPackaging()
+ " as an unpacked configuration");
File destinationDir = new File(deployDir, getDeploySubDir("configuration"));
Artifact artifact = project.getArtifact();
if (artifact == null) {
getLog().error(
"No Artifact found in project " + getProjectId());
throw new MojoFailureException(
"No Artifact found in project");
}
File artifactFile = artifact.getFile();
if (artifactFile == null) {
artifactResolver.resolve(artifact, remoteRepositories,
artifactRepository);
artifactFile = artifact.getFile();
}
if (artifactFile == null) {
getLog().error(
"Artifact File is null for " + getProjectId());
throw new MojoFailureException("Artifact File is null ");
}
getLog().info(
"Unpacking " + artifactFile + " to " + destinationDir);
destinationDir.mkdirs();
// we use a zip unarchiver
unpack(artifactFile, destinationDir, "zip" , false);
} else if ("war".equals(packaging)) {
// UseCase: war webapp
// deploy to webapps but dont unpack
getLog().info(
"Deploying " + project.getGroupId() + ":"
+ project.getArtifactId() + ":"
+ project.getPackaging() + " as a webapp");
deployProjectArtifact(new File(deployDir, getDeploySubDir("webapps")), false,
true);
} else if ("jar".equals(packaging)) {
// UseCase: jar, marked with a property
// deploy the target
Properties p = project.getProperties();
String deployTarget = p.getProperty("deploy.target");
if ("shared".equals(deployTarget)) {
deployProjectArtifact(new File(deployDir, getDeploySubDir("shared/lib")),
true, false);
} else if ("common".equals(deployTarget)) {
deployProjectArtifact(new File(deployDir, getDeploySubDir("common/lib")),
true, false);
} else if ("endorsed".equals(deployTarget)) {
deployProjectArtifact(new File(deployDir, getDeploySubDir("endorsed")),
true, false);
} else if ("server".equals(deployTarget)) {
deployProjectArtifact(new File(deployDir, getDeploySubDir("server/lib")),
true, false);
} else {
getLog().info(
"No deployment specification -- skipping "
+ getProjectId());
}
} else if ("pom".equals(packaging)) {
// UseCase: pom, marked with a property
// deploy the contents
Properties p = project.getProperties();
String deployTarget = p.getProperty("deploy.target");
if ("shared".equals(deployTarget)) {
File destinationDir = new File(deployDir, getDeploySubDir("shared/lib"));
destinationDir.mkdirs();
deployArtifacts(artifacts, destinationDir);
} else if ("common".equals(deployTarget)) {
File destinationDir = new File(deployDir, getDeploySubDir("common/lib"));
destinationDir.mkdirs();
deployArtifacts(artifacts, destinationDir);
} else if ("endorsed".equals(deployTarget)) {
File destinationDir = new File(deployDir, getDeploySubDir("endorsed/lib"));
destinationDir.mkdirs();
deployArtifacts(artifacts, destinationDir);
} else if ("server".equals(deployTarget)) {
File destinationDir = new File(deployDir, getDeploySubDir("server/lib"));
destinationDir.mkdirs();
deployArtifacts(artifacts, destinationDir);
} else if ("webbapps".equals(deployTarget)) {
File destinationDir = new File(deployDir, getDeploySubDir("webbapps"));
destinationDir.mkdirs();
deployArtifacts(artifacts, destinationDir);
} else if ( "tomcat-overlay".equals(deployTarget)) {
String cleanTargetPaths = p.getProperty("clean.targets");
String[] cleanPaths = cleanTargetPaths.split(";");
for ( String pathToClean : cleanPaths ) {
File destinationDir = new File(deployDir, getDeploySubDir(pathToClean));
getLog().info("Deleting "+destinationDir);
deleteAll(destinationDir);
}
deployDir.mkdirs();
deployOverlay(artifacts, deployDir);
} else {
getLog().info(
"No deployment specification -- skipping "
+ getProjectId());
}
} else {
getLog().info(
"No deployment specification -- skipping "
+ getProjectId());
}
} catch (IOException ex) {
getLog().debug("Failed to deploy to container ", ex);
throw new MojoFailureException("Failed to deploy to container :"
+ ex.getMessage());
} catch (NoSuchArchiverException ex) {
getLog().debug("Failed to deploy to container ", ex);
throw new MojoFailureException("Failed to deploy to container :"
+ ex.getMessage());
} catch (AbstractArtifactResolutionException ex) {
getLog().debug("Failed to deploy to container ", ex);
throw new MojoFailureException("Failed to deploy to container :"
+ ex.getMessage());
}
}
/**
* @param string
* @param string2
* @return
*/
private String getDeploySubDir(String key)
{
if ( locationMap == null ) {
if ( appServer != null ) {
try
{
InputStream in = getClass().getClassLoader().getResourceAsStream(
"deploy." + appServer + ".properties");
Properties p = new Properties();
p.load(in);
in.close();
locationMap = p;
}
catch (Exception ex)
{
this.getLog().warn("No Config for appserver "+appServer+" cause:"+ex.getMessage());
}
}
if ( locationMap == null ) {
locationMap = defaultLocationMap;
}
}
String deploySubDir = locationMap.getProperty(key);
if ( deploySubDir == null || deploySubDir.trim().length() == 0 ) {
deploySubDir = defaultLocationMap.getProperty(key);
}
if (deploySubDir == null ) {
deploySubDir = key;
}
if ( !deploySubDir.endsWith("/") ) {
deploySubDir = deploySubDir + "/";
}
return deploySubDir;
}
protected void deployOverlay(Set artifacts, File destination)
throws IOException, MojoFailureException,
AbstractArtifactResolutionException, MojoExecutionException, NoSuchArchiverException {
for (Iterator iter = artifacts.iterator(); iter.hasNext();) {
Artifact artifact = (Artifact) iter.next();
if (artifact == null) {
getLog().error(
"Null Artifact found, sould never happen, in artifacts for project "
+ getProjectId());
throw new MojoFailureException(
"Null Artifact found, sould never happen, in artifacts for project ");
}
File artifactFile = artifact.getFile();
if (artifactFile == null) {
artifactResolver.resolve(artifact, remoteRepositories,
artifactRepository);
artifactFile = artifact.getFile();
}
if (artifactFile == null) {
getLog().error(
"Artifact File is null for dependency "
+ artifact.getId() + " in " + getProjectId());
throw new MojoFailureException(
"Artifact File is null for dependency "
+ artifact.getId() + " in " + getProjectId());
}
getLog().debug("Processing: " + artifact.getId());
if ( !"test".equals(artifact.getScope()) ) {
unpack(artifact.getFile(), destination, artifact.getType(),true);
}
}
}
protected void deployArtifacts(Set artifacts, File destination)
throws IOException, MojoFailureException,
AbstractArtifactResolutionException {
for (Iterator iter = artifacts.iterator(); iter.hasNext();) {
Artifact artifact = (Artifact) iter.next();
if (artifact == null) {
getLog().error(
"Null Artifact found, sould never happen, in artifacts for project "
+ getProjectId());
throw new MojoFailureException(
"Null Artifact found, sould never happen, in artifacts for project ");
}
File artifactFile = artifact.getFile();
if (artifactFile == null) {
artifactResolver.resolve(artifact, remoteRepositories,
artifactRepository);
artifactFile = artifact.getFile();
}
if (artifactFile == null) {
getLog().error(
"Artifact File is null for dependency "
+ artifact.getId() + " in " + getProjectId());
throw new MojoFailureException(
"Artifact File is null for dependency "
+ artifact.getId() + " in " + getProjectId());
}
String targetFileName = getDefaultFinalName(artifact);
getLog().debug("Processing: " + targetFileName);
File destinationFile = new File(destination, targetFileName);
if ("provided".equals(artifact.getScope())
|| "test".equals(artifact.getScope())) {
getLog().info(
"Skipping " + artifactFile + " Scope "
+ artifact.getScope());
} else {
getLog()
.info("Copy " + artifactFile + " to " + destinationFile);
copyFileIfModified(artifact.getFile(), destinationFile);
}
}
}
private void deployProjectArtifact(File destination, boolean withVersion,
boolean deleteStub) throws MojoFailureException, IOException,
AbstractArtifactResolutionException, NoSuchArchiverException, MojoExecutionException {
Artifact artifact = project.getArtifact();
String fileName = null;
String stubName = null;
if (withVersion) {
fileName = getDeployId() + "-" + project.getVersion()
+ "." + project.getPackaging();
stubName = getDeployId() + "-" + project.getVersion();
} else {
fileName = getDeployId() + "." + project.getPackaging();
stubName = getDeployId();
}
File destinationFile = new File(destination, fileName);
File stubFile = new File(destination, stubName);
Set artifacts = project.getArtifacts();
getLog().info("Found " + artifacts.size() + " artifacts");
for (Iterator i = artifacts.iterator(); i.hasNext();) {
Artifact a = (Artifact) i.next();
getLog()
.info(
"Artifact Id " + a.getArtifactId() + " file "
+ a.getFile());
}
if (artifact == null) {
getLog().error("No Artifact found in project " + getProjectId());
throw new MojoFailureException(
"No Artifact found in project, target was "
+ destinationFile);
}
File artifactFile = artifact.getFile();
if (artifactFile == null) {
artifactResolver.resolve(artifact, remoteRepositories,
artifactRepository);
artifactFile = artifact.getFile();
}
if (artifactFile == null) {
getLog().error(
"Artifact File is null for " + getProjectId()
+ ", target was " + destinationFile);
throw new MojoFailureException("Artifact File is null ");
}
if ("war".equals(project.getPackaging()) && isExplodeWars()) {
if (stubFile.exists()) {
deleteAll(stubFile);
}
stubFile.mkdirs();
unpack(artifactFile, stubFile, artifact.getType(), true);
} else {
if (deleteStub && stubFile.exists()) {
deleteAll(stubFile);
}
destinationFile.getParentFile().mkdirs();
if (withVersion) {
// This bails out in an exception if there is a problem.
handleDuplicates(destination, fileName);
}
getLog().info("Copy " + artifactFile + " to " + destinationFile);
copyFileIfModified(artifactFile, destinationFile);
}
}
/**
* This checks for duplicates that may cause problems.
* @param destination The folder into which we are deploying.
* @param fileName The name of the file we're deploying
*/
private void handleDuplicates(File destination, String fileName)
throws IOException, MojoFailureException {
// Check there aren't other versions already deployed.
List<File> existing = FileUtils.getFiles(destination, getDeployId()+ "*", fileName, true);
if (!existing.isEmpty()) {
if (cleanup) {
// Remove the files that may cause a problem.
for (File file: existing) {
if (file.delete()) {
getLog().info("Removed: "+ file);
} else {
throw new MojoFailureException("Could not delete: "+ file);
}
}
} else {
throw new MojoFailureException("Existing version(s) of artifact already deployed to "+ destination+
" please remove ("+ StringUtils.join(existing.iterator(), ", ")+ ") or specify -Dsakai.cleanup=true");
}
}
}
}