Java tutorial
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.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import org.apache.maven.archiver.MavenArchiveConfiguration; import org.apache.maven.archiver.MavenArchiver; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.factory.ArtifactFactory; 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.model.Resource; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.Component; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.archiver.ArchiverException; import org.codehaus.plexus.archiver.UnArchiver; import org.codehaus.plexus.archiver.jar.JarArchiver; import org.codehaus.plexus.archiver.manager.ArchiverManager; import org.codehaus.plexus.archiver.manager.NoSuchArchiverException; import org.codehaus.plexus.util.*; public abstract class AbstractComponentMojo extends AbstractMojo { /** * The maven project. */ @Parameter(defaultValue = "${project}", required = true, readonly = true) protected MavenProject project; /** * The directory containing generated classes. */ @Parameter(defaultValue = "${project.build.outputDirectory}", required = true, readonly = true) private File classesDirectory; /** * Whether a JAR file will be created for the classes in the webapp. Using * this optional configuration parameter will make the generated classes to * be archived into a jar file and the classes directory will then be * excluded from the webapp. * */ @Parameter(property = "archiveClasses", defaultValue = "false") private boolean archiveClasses; /** * The Jar archiver needed for archiving classes directory into jar file * under WEB-INF/lib. */ @Component(role = org.codehaus.plexus.archiver.Archiver.class, hint = "jar") private JarArchiver jarArchiver; /** * The directory where the webapp is built. */ @Parameter(defaultValue = "${project.build.directory}/${project.build.finalName}", required = true) private File webappDirectory; /** * Single directory for extra files to include in the WAR. */ @Parameter(defaultValue = "${basedir}/src/main/webapp", required = true) private File warSourceDirectory; /** * The list of webResources we want to transfer. */ @Parameter private Resource[] webResources; /** * Filters (property files) to include during the interpolation of the * pom.xml. */ @Parameter(defaultValue = "${project.build.filters}") private List filters; /** * The path to the web.xml file to use. */ @Parameter(property = "maven.war.webxml") private File webXml; /** * The path to the context.xml file to use. */ @Parameter(property = "maven.war.containerConfigXML") private File containerConfigXML; /** * Directory to unpack dependent WARs into if needed */ @Parameter(defaultValue = "${project.build.directory}/war/work", required = true) private File workDirectory; @Component protected ArtifactFactory artifactFactory; @Component protected ArtifactResolver artifactResolver; @Parameter(defaultValue = "${localRepository}") protected ArtifactRepository artifactRepository; @Parameter(defaultValue = "${project.remoteArtifactRepositories}") protected List remoteRepositories; /** * To look up Archiver/UnArchiver implementations */ @Component(role = org.codehaus.plexus.archiver.manager.ArchiverManager.class) protected ArchiverManager archiverManager; private static final String WEB_INF = "WEB-INF"; private static final String META_INF = "META-INF"; private static final String[] DEFAULT_INCLUDES = { "**/**" }; /** * The comma separated list of tokens to include in the WAR. Default is * '**'. */ @Parameter(alias = "includes") private String warSourceIncludes = "**"; /** * The comma separated list of tokens to exclude from the WAR. */ @Parameter(alias = "excludes") private String warSourceExcludes; /** * The comma separated list of tokens to include when doing a war overlay. * Default is '**' */ @Parameter private String dependentWarIncludes = "**"; /** * The comma separated list of tokens to exclude when doing a war overlay. */ @Parameter private String dependentWarExcludes; /** * The maven archive configuration to use. */ @Parameter protected MavenArchiveConfiguration archive = new MavenArchiveConfiguration(); private static final String[] EMPTY_STRING_ARRAY = {}; public MavenProject getProject() { return project; } public void setProject(MavenProject project) { this.project = project; } public File getClassesDirectory() { return classesDirectory; } public void setClassesDirectory(File classesDirectory) { this.classesDirectory = classesDirectory; } public File getWebappDirectory() { return webappDirectory; } public void setWebappDirectory(File webappDirectory) { this.webappDirectory = webappDirectory; } public File getWarSourceDirectory() { return warSourceDirectory; } public void setWarSourceDirectory(File warSourceDirectory) { this.warSourceDirectory = warSourceDirectory; } public File getWebXml() { return webXml; } public void setWebXml(File webXml) { this.webXml = webXml; } public File getContainerConfigXML() { return containerConfigXML; } public void setContainerConfigXML(File containerConfigXML) { this.containerConfigXML = containerConfigXML; } /** * Returns a string array of the excludes to be used when assembling/copying * the war. * * @return an array of tokens to exclude */ protected String[] getExcludes() { List excludeList = new ArrayList(); if (StringUtils.isNotEmpty(warSourceExcludes)) { excludeList.addAll(Arrays.asList(StringUtils.split(warSourceExcludes, ","))); } // if webXML is specified, omit the one in the source directory if (webXml != null && StringUtils.isNotEmpty(webXml.getName())) { excludeList.add("**/" + WEB_INF + "/web.xml"); } // if contextXML is specified, omit the one in the source directory if (containerConfigXML != null && StringUtils.isNotEmpty(containerConfigXML.getName())) { excludeList.add("**/" + META_INF + "/" + containerConfigXML.getName()); } return (String[]) excludeList.toArray(EMPTY_STRING_ARRAY); } /** * Returns a string array of the includes to be used when assembling/copying * the war. * * @return an array of tokens to include */ protected String[] getIncludes() { return StringUtils.split(StringUtils.defaultString(warSourceIncludes), ","); } /** * Returns a string array of the excludes to be used when adding dependent * wars as an overlay onto this war. * * @return an array of tokens to exclude */ protected String[] getDependentWarExcludes() { String[] excludes; if (StringUtils.isNotEmpty(dependentWarExcludes)) { excludes = StringUtils.split(dependentWarExcludes, ","); } else { excludes = EMPTY_STRING_ARRAY; } return excludes; } /** * Returns a string array of the includes to be used when adding dependent * wars as an overlay onto this war. * * @return an array of tokens to include */ protected String[] getDependentWarIncludes() { return StringUtils.split(StringUtils.defaultString(dependentWarIncludes), ","); } protected String getProjectId() { return project.getGroupId() + ":" + project.getArtifactId() + ":" + project.getPackaging() + ":" + project.getVersion(); } public void deleteAll(File dir) { if (dir.isDirectory()) { File[] files = dir.listFiles(); for (int i = 0; i < files.length; i++) { if (files[i].isDirectory()) { deleteAll(files[i]); } else { files[i].delete(); } } } dir.delete(); } public void buildExplodedWebapp(File webappDirectory) throws MojoExecutionException, MojoFailureException { getLog().info("Exploding webapp..."); webappDirectory.mkdirs(); try { buildWebapp(project, webappDirectory); } catch (IOException e) { throw new MojoExecutionException("Could not explode webapp...", e); } } private Map getBuildFilterProperties() throws MojoExecutionException { Map filterProperties = new Properties(); // System properties filterProperties.putAll(System.getProperties()); // Project properties filterProperties.putAll(project.getProperties()); for (Iterator i = filters.iterator(); i.hasNext();) { String filtersfile = (String) i.next(); try { Properties properties = PropertyUtils.loadPropertyFile(new File(filtersfile), true, true); filterProperties.putAll(properties); } catch (IOException e) { throw new MojoExecutionException("Error loading property file '" + filtersfile + "'", e); } } // can't putAll, as ReflectionProperties doesn't enumerate - so we make // a composite map with the project variables as dominant return new CompositeMap(new ReflectionProperties(project), filterProperties); } /** * Copies webapp webResources from the specified directory. <p/> Note that * the <tt>webXml</tt> parameter could be null and may specify a file * which is not named <tt>web.xml<tt>. If the file * exists, it will be copied to the <tt>META-INF</tt> directory and * renamed accordingly. * * @param resource the resource to copy * @param webappDirectory the target directory * @param filterProperties * @throws java.io.IOException if an error occured while copying webResources */ public void copyResources(Resource resource, File webappDirectory, Map filterProperties) throws IOException { if (!resource.getDirectory().equals(webappDirectory.getPath())) { getLog().info("Copy webapp webResources to " + webappDirectory.getAbsolutePath()); if (webappDirectory.exists()) { String[] fileNames = getWarFiles(resource); String targetPath = (resource.getTargetPath() == null) ? "" : resource.getTargetPath(); File destination = new File(webappDirectory, targetPath); for (int i = 0; i < fileNames.length; i++) { if (resource.isFiltering()) { copyFilteredFile(new File(resource.getDirectory(), fileNames[i]), new File(destination, fileNames[i]), null, getFilterWrappers(), filterProperties); } else { copyFileIfModified(new File(resource.getDirectory(), fileNames[i]), new File(destination, fileNames[i])); } } } } } /** * Copies webapp webResources from the specified directory. <p/> Note that * the <tt>webXml</tt> parameter could be null and may specify a file * which is not named <tt>web.xml<tt>. If the file * exists, it will be copied to the <tt>META-INF</tt> directory and * renamed accordingly. * * @param sourceDirectory the source directory * @param webappDirectory the target directory * @throws java.io.IOException if an error occured while copying webResources */ public void copyResources(File sourceDirectory, File webappDirectory) throws IOException { if (!sourceDirectory.equals(webappDirectory)) { getLog().info("Copy webapp webResources to " + webappDirectory.getAbsolutePath()); if (warSourceDirectory.exists()) { String[] fileNames = getWarFiles(sourceDirectory); for (int i = 0; i < fileNames.length; i++) { copyFileIfModified(new File(sourceDirectory, fileNames[i]), new File(webappDirectory, fileNames[i])); } } } } /** * Generates the JAR. * * @todo Add license files in META-INF directory. */ public void createJarArchive(File libDirectory) throws MojoExecutionException { String archiveName = project.getBuild().getFinalName() + ".jar"; File jarFile = new File(libDirectory, archiveName); MavenArchiver archiver = new MavenArchiver(); archiver.setArchiver(jarArchiver); archiver.setOutputFile(jarFile); try { archiver.getArchiver().addDirectory(classesDirectory, getIncludes(), getExcludes()); archiver.createArchive(null, project, archive); } catch (Exception e) { // TODO: improve error handling throw new MojoExecutionException("Error assembling JAR", e); } } protected void checkComponentWebXmlExists(File webXml) { try { if (!webXml.exists()) { FileWriter fw = new FileWriter(webXml); fw.write(""); fw.close(); } } catch (IOException ex) { ex.printStackTrace(); } } /** * Builds the webapp for the specified project. <p/> Classes, libraries and * tld files are copied to the <tt>webappDirectory</tt> during this phase. * * @param project * the maven project * @param webappDirectory * @throws java.io.IOException * if an error occured while building the webapp */ public void buildWebapp(MavenProject project, File webappDirectory) throws MojoExecutionException, IOException, MojoFailureException { getLog().info("Assembling webapp " + project.getArtifactId() + " in " + webappDirectory); File webinfDir = new File(webappDirectory, WEB_INF); webinfDir.mkdirs(); File metainfDir = new File(webappDirectory, META_INF); metainfDir.mkdirs(); List webResources = this.webResources != null ? Arrays.asList(this.webResources) : null; if (webResources != null && webResources.size() > 0) { Map filterProperties = getBuildFilterProperties(); for (Iterator it = webResources.iterator(); it.hasNext();) { Resource resource = (Resource) it.next(); copyResources(resource, webappDirectory, filterProperties); } } copyResources(warSourceDirectory, webappDirectory); if (webXml != null && StringUtils.isNotEmpty(webXml.getName())) { if (!webXml.exists()) { throw new MojoFailureException("The specified web.xml file '" + webXml + "' does not exist"); } // rename to web.xml copyFileIfModified(webXml, new File(webinfDir, "/web.xml")); } checkComponentWebXmlExists(new File(webinfDir, "/web.xml")); if (containerConfigXML != null && StringUtils.isNotEmpty(containerConfigXML.getName())) { metainfDir = new File(webappDirectory, META_INF); String xmlFileName = containerConfigXML.getName(); copyFileIfModified(containerConfigXML, new File(metainfDir, xmlFileName)); } File libDirectory = new File(webinfDir, "lib"); File tldDirectory = new File(webinfDir, "tld"); File webappClassesDirectory = new File(webappDirectory, WEB_INF + "/classes"); if (classesDirectory.exists() && !classesDirectory.equals(webappClassesDirectory)) { if (archiveClasses) { createJarArchive(libDirectory); } else { copyDirectoryStructureIfModified(classesDirectory, webappClassesDirectory); } } Set artifacts = project.getArtifacts(); List duplicates = findDuplicates(artifacts); List dependentWarDirectories = new ArrayList(); for (Iterator iter = artifacts.iterator(); iter.hasNext();) { Artifact artifact = (Artifact) iter.next(); String targetFileName = getDefaultFinalName(artifact); getLog().debug("Processing: " + targetFileName); if (duplicates.contains(targetFileName)) { getLog().debug("Duplicate found: " + targetFileName); targetFileName = artifact.getGroupId() + "-" + targetFileName; getLog().debug("Renamed to: " + targetFileName); } // TODO: utilise appropriate methods from project builder ScopeArtifactFilter filter = new ScopeArtifactFilter(Artifact.SCOPE_RUNTIME); if (!artifact.isOptional() && filter.include(artifact)) { String type = artifact.getType(); if ("tld".equals(type)) { copyFileIfModified(artifact.getFile(), new File(tldDirectory, targetFileName)); } else { if ("jar".equals(type) || "ejb".equals(type) || "ejb-client".equals(type)) { copyFileIfModified(artifact.getFile(), new File(libDirectory, targetFileName)); } else { if ("par".equals(type)) { targetFileName = targetFileName.substring(0, targetFileName.lastIndexOf('.')) + ".jar"; getLog().debug("Copying " + artifact.getFile() + " to " + new File(libDirectory, targetFileName)); copyFileIfModified(artifact.getFile(), new File(libDirectory, targetFileName)); } else { if ("war".equals(type)) { dependentWarDirectories.add(unpackWarToTempDirectory(artifact)); } else { getLog().debug("Skipping artifact of type " + type + " for WEB-INF/lib"); } } } } } } if (dependentWarDirectories.size() > 0) { getLog().info("Overlaying " + dependentWarDirectories.size() + " war(s)."); // overlay dependent wars for (Iterator iter = dependentWarDirectories.iterator(); iter.hasNext();) { copyDependentWarContents((File) iter.next(), webappDirectory); } } } /** * Searches a set of artifacts for duplicate filenames and returns a list of * duplicates. * * @param artifacts * set of artifacts * @return List of duplicated artifacts */ private List findDuplicates(Set artifacts) { List duplicates = new ArrayList(); List identifiers = new ArrayList(); for (Iterator iter = artifacts.iterator(); iter.hasNext();) { Artifact artifact = (Artifact) iter.next(); String candidate = getDefaultFinalName(artifact); if (identifiers.contains(candidate)) { duplicates.add(candidate); } else { identifiers.add(candidate); } } return duplicates; } /** * Unpacks war artifacts into a temporary directory inside * <tt>workDirectory</tt> named with the name of the war. * * @param artifact * War artifact to unpack. * @return Directory containing the unpacked war. * @throws MojoExecutionException */ private File unpackWarToTempDirectory(Artifact artifact) throws MojoExecutionException { String name = artifact.getFile().getName(); File tempLocation = new File(workDirectory, name.substring(0, name.length() - 4)); boolean process = false; if (!tempLocation.exists()) { tempLocation.mkdirs(); process = true; } else if (artifact.getFile().lastModified() > tempLocation.lastModified()) { process = true; } if (process) { File file = artifact.getFile(); try { unpack(file, tempLocation, false); } catch (NoSuchArchiverException e) { this.getLog().info("Skip unpacking dependency file with unknown extension: " + file.getPath()); } } return tempLocation; } /** * Unpacks the archive file. * * @param file * File to be unpacked. * @param location * Location where to put the unpacked files. */ private void unpack(File file, File location, boolean overwrite) throws MojoExecutionException, NoSuchArchiverException { String archiveExt = FileUtils.getExtension(file.getAbsolutePath()).toLowerCase(); unpack(file, location, archiveExt, overwrite); } /** * Unpacks an archive with a given type * @param file the file to be unpacked * @param location the location to unpack the file to * @param archiveExt the archive type/extension * @throws MojoExecutionException * @throws NoSuchArchiverException */ protected void unpack(File file, File location, String archiveExt, boolean overwrite) throws MojoExecutionException, NoSuchArchiverException { try { UnArchiver unArchiver = archiverManager.getUnArchiver(archiveExt); unArchiver.setSourceFile(file); unArchiver.setDestDirectory(location); unArchiver.setOverwrite(overwrite); unArchiver.extract(); } catch (ArchiverException e) { throw new MojoExecutionException("Error unpacking file: " + file + "to: " + location, e); } } /** * Recursively copies contents of <tt>srcDir</tt> into <tt>targetDir</tt>. * This will not overwrite any existing files. * * @param srcDir * Directory containing unpacked dependent war contents * @param targetDir * Directory to overlay srcDir into */ private void copyDependentWarContents(File srcDir, File targetDir) throws MojoExecutionException { DirectoryScanner scanner = new DirectoryScanner(); scanner.setBasedir(srcDir); scanner.setExcludes(getDependentWarExcludes()); scanner.addDefaultExcludes(); scanner.setIncludes(getDependentWarIncludes()); scanner.scan(); String[] dirs = scanner.getIncludedDirectories(); for (int j = 0; j < dirs.length; j++) { new File(targetDir, dirs[j]).mkdirs(); } String[] files = scanner.getIncludedFiles(); for (int j = 0; j < files.length; j++) { File targetFile = new File(targetDir, files[j]); try { // Don't copy if it is in the source directory if (!new File(warSourceDirectory, files[j]).exists()) { targetFile.getParentFile().mkdirs(); copyFileIfModified(new File(srcDir, files[j]), targetFile); } } catch (IOException e) { throw new MojoExecutionException("Error copying file '" + files[j] + "' to '" + targetFile + "'", e); } } } /** * Returns a list of filenames that should be copied over to the destination * directory. * * @param sourceDir * the directory to be scanned * @return the array of filenames, relative to the sourceDir */ private String[] getWarFiles(File sourceDir) { DirectoryScanner scanner = new DirectoryScanner(); scanner.setBasedir(sourceDir); scanner.setExcludes(getExcludes()); scanner.addDefaultExcludes(); scanner.setIncludes(getIncludes()); scanner.scan(); return scanner.getIncludedFiles(); } /** * Returns a list of filenames that should be copied over to the destination * directory. * * @param resource * the resource to be scanned * @return the array of filenames, relative to the sourceDir */ private String[] getWarFiles(Resource resource) { DirectoryScanner scanner = new DirectoryScanner(); scanner.setBasedir(resource.getDirectory()); if (resource.getIncludes() != null && !resource.getIncludes().isEmpty()) { scanner.setIncludes((String[]) resource.getIncludes().toArray(EMPTY_STRING_ARRAY)); } else { scanner.setIncludes(DEFAULT_INCLUDES); } if (resource.getExcludes() != null && !resource.getExcludes().isEmpty()) { scanner.setExcludes((String[]) resource.getExcludes().toArray(EMPTY_STRING_ARRAY)); } scanner.addDefaultExcludes(); scanner.scan(); return scanner.getIncludedFiles(); } /** * Copy file from source to destination only if source is newer than the * target file. If <code>destinationDirectory</code> does not exist, it * (and any parent directories) will be created. If a file * <code>source</code> in <code>destinationDirectory</code> exists, it * will be overwritten. * * @param source * An existing <code>File</code> to copy. * @param destinationDirectory * A directory to copy <code>source</code> into. * @throws java.io.FileNotFoundException * if <code>source</code> isn't a normal file. * @throws IllegalArgumentException * if <code>destinationDirectory</code> isn't a directory. * @throws java.io.IOException * if <code>source</code> does not exist, the file in * <code>destinationDirectory</code> cannot be written to, or * an IO error occurs during copying. <p/> TO DO: Remove this * method when Maven moves to plexus-utils version 1.4 */ private static void copyFileToDirectoryIfModified(File source, File destinationDirectory) throws IOException { // TO DO: Remove this method and use the method in WarFileUtils when // Maven 2 changes // to plexus-utils 1.2. if (destinationDirectory.exists() && !destinationDirectory.isDirectory()) { throw new IllegalArgumentException("Destination is not a directory"); } copyFileIfModified(source, new File(destinationDirectory, source.getName())); } private FilterWrapper[] getFilterWrappers() { return new FilterWrapper[] { // support ${token} new FilterWrapper() { public Reader getReader(Reader fileReader, Map filterProperties) { return new InterpolationFilterReader(fileReader, filterProperties, "${", "}"); } }, // support @token@ new FilterWrapper() { public Reader getReader(Reader fileReader, Map filterProperties) { return new InterpolationFilterReader(fileReader, filterProperties, "@", "@"); } } }; } /** * @param from * @param to * @param encoding * @param wrappers * @param filterProperties * @throws IOException * TO DO: Remove this method when Maven moves to plexus-utils * version 1.4 */ private static void copyFilteredFile(File from, File to, String encoding, FilterWrapper[] wrappers, Map filterProperties) throws IOException { // buffer so it isn't reading a byte at a time! Reader fileReader = null; Writer fileWriter = null; try { // fix for MWAR-36, ensures that the parent dir are created first to.getParentFile().mkdirs(); if (encoding == null || encoding.length() < 1) { fileReader = new BufferedReader(new FileReader(from)); fileWriter = new FileWriter(to); } else { FileInputStream instream = new FileInputStream(from); FileOutputStream outstream = new FileOutputStream(to); fileReader = new BufferedReader(new InputStreamReader(instream, encoding)); fileWriter = new OutputStreamWriter(outstream, encoding); } Reader reader = fileReader; for (int i = 0; i < wrappers.length; i++) { FilterWrapper wrapper = wrappers[i]; reader = wrapper.getReader(reader, filterProperties); } IOUtil.copy(reader, fileWriter); } finally { IOUtil.close(fileReader); IOUtil.close(fileWriter); } } /** * Copy file from source to destination only if source timestamp is later * than the destination timestamp. The directories up to * <code>destination</code> will be created if they don't already exist. * <code>destination</code> will be overwritten if it already exists. * * @param source * An existing non-directory <code>File</code> to copy bytes * from. * @param destination * A non-directory <code>File</code> to write bytes to * (possibly overwriting). * @throws IOException * if <code>source</code> does not exist, * <code>destination</code> cannot be written to, or an IO * error occurs during copying. * @throws java.io.FileNotFoundException * if <code>destination</code> is a directory <p/> TO DO: * Remove this method when Maven moves to plexus-utils version * 1.4 */ protected static void copyFileIfModified(File source, File destination) throws IOException { // TO DO: Remove this method and use the method in WarFileUtils when // Maven 2 changes // to plexus-utils 1.2. if (destination.lastModified() < source.lastModified()) { FileUtils.copyFile(source.getCanonicalFile(), destination); // preserve timestamp destination.setLastModified(source.lastModified()); } } /** * Copies a entire directory structure but only source files with timestamp * later than the destinations'. <p/> Note: * <ul> * <li>It will include empty directories. * <li>The <code>sourceDirectory</code> must exists. * </ul> * * @param sourceDirectory * @param destinationDirectory * @throws IOException * TO DO: Remove this method when Maven moves to plexus-utils * version 1.4 */ private static void copyDirectoryStructureIfModified(File sourceDirectory, File destinationDirectory) throws IOException { if (!sourceDirectory.exists()) { throw new IOException("Source directory doesn't exists (" + sourceDirectory.getAbsolutePath() + ")."); } File[] files = sourceDirectory.listFiles(); String sourcePath = sourceDirectory.getAbsolutePath(); for (int i = 0; i < files.length; i++) { File file = files[i]; String dest = file.getAbsolutePath(); dest = dest.substring(sourcePath.length() + 1); File destination = new File(destinationDirectory, dest); if (file.isFile()) { destination = destination.getParentFile(); copyFileToDirectoryIfModified(file, destination); } else if (file.isDirectory()) { if (!destination.exists() && !destination.mkdirs()) { throw new IOException( "Could not create destination directory '" + destination.getAbsolutePath() + "'."); } copyDirectoryStructureIfModified(file, destination); } else { throw new IOException("Unknown file type: " + file.getAbsolutePath()); } } } /** * TO DO: Remove this interface when Maven moves to plexus-utils version 1.4 */ private interface FilterWrapper { Reader getReader(Reader fileReader, Map filterProperties); } /** * Converts the filename of an artifact to artifactId-version.type format. * * @param artifact * @return converted filename of the artifact */ protected String getDefaultFinalName(Artifact artifact) { String finalName = artifact.getArtifactId() + "-" + artifact.getVersion(); String classifier = artifact.getClassifier(); if ((classifier != null) && !("".equals(classifier.trim()))) { finalName += "-" + classifier; } finalName = finalName + "." + artifact.getArtifactHandler().getExtension(); return finalName; } }