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"); } } } }