org.piraso.maven.AbstractWarMojo.java Source code

Java tutorial

Introduction

Here is the source code for org.piraso.maven.AbstractWarMojo.java

Source

package org.piraso.maven;

/*
 * 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 org.apache.maven.archiver.MavenArchiveConfiguration;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.execution.MavenSession;
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.plugin.logging.Log;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.shared.filtering.MavenFileFilter;
import org.apache.maven.shared.filtering.MavenFilteringException;
import org.apache.maven.shared.filtering.MavenResourcesExecution;
import org.apache.maven.shared.filtering.MavenResourcesFiltering;
import org.codehaus.plexus.archiver.Archiver;
import org.codehaus.plexus.archiver.jar.JarArchiver;
import org.codehaus.plexus.archiver.manager.ArchiverManager;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.StringUtils;
import org.piraso.maven.overlay.OverlayManager;
import org.piraso.maven.packaging.*;
import org.piraso.maven.util.WebappStructure;
import org.piraso.maven.util.WebappStructureSerializer;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * Contains common jobs for WAR mojos.
 *
 * @version $Id: AbstractWarMojo.java 1391186 2012-09-27 19:36:49Z krosenvold $
 */
public abstract class AbstractWarMojo extends AbstractMojo {
    public static final String DEFAULT_FILE_NAME_MAPPING = "@{artifactId}@-@{version}@.@{extension}@";

    public static final String DEFAULT_FILE_NAME_MAPPING_CLASSIFIER = "@{artifactId}@-@{version}@-@{classifier}@.@{extension}@";

    private static final String[] EMPTY_STRING_ARRAY = {};

    private static final String META_INF = "META-INF";

    private static final String WEB_INF = "WEB-INF";

    /**
     * The Maven project.
     */
    @Component
    private MavenProject project;

    /**
     * The directory containing compiled 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 compiled classes to be archived into a JAR file
     * and the classes directory will then be excluded from the webapp.
     *
     * @since 2.0.1
     */
    @Parameter(property = "archiveClasses", defaultValue = "false")
    private boolean archiveClasses;

    /**
     * The encoding to use when copying filtered web resources.
     *
     * @since 2.3
     */
    @Parameter(property = "resourceEncoding", defaultValue = "${project.build.sourceEncoding}")
    private String resourceEncoding;

    /**
     * The JAR archiver needed for archiving the classes directory into a JAR file under WEB-INF/lib.
     */
    @Component(role = 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. This is where
     * you place your JSP files.
     */
    @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
    private List<String> filters;

    /**
     * The path to the web.xml file to use.
     */
    @Parameter(property = "maven.war.webxml")
    private File webXml;

    /**
     * The path to a configuration file for the servlet container. Note that
     * the file name may be different for different servlet containers.
     * Apache Tomcat uses a configuration file named context.xml. The file will
     * be copied to the META-INF directory.
     */
    @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;

    /**
     * The file name mapping to use when copying libraries and TLDs. If no file mapping is
     * set (default) the files are copied with their standard names.
     *
     * @since 2.1-alpha-1
     */
    @Parameter
    private String outputFileNameMapping;

    /**
     * The file containing the webapp structure cache.
     *
     * @since 2.1-alpha-1
     */
    @Parameter(defaultValue = "${project.build.directory}/war/work/webapp-cache.xml", required = true)
    private File cacheFile;

    /**
     * Whether the cache should be used to save the status of the webapp
     * across multiple runs. Experimental feature so disabled by default.
     *
     * @since 2.1-alpha-1
     */
    @Parameter(property = "useCache", defaultValue = "false")
    private boolean useCache = false;

    /**
     */
    @Component(role = ArtifactFactory.class)
    private ArtifactFactory artifactFactory;

    /**
     * To look up Archiver/UnArchiver implementations.
     */
    @Component(role = ArchiverManager.class)
    private ArchiverManager archiverManager;

    /**
     */
    @Component(role = MavenFileFilter.class, hint = "default")
    private MavenFileFilter mavenFileFilter;

    /**
     */
    @Component(role = MavenResourcesFiltering.class, hint = "default")
    private MavenResourcesFiltering mavenResourcesFiltering;

    /**
     * The comma separated list of tokens to include when copying the content
     * of the warSourceDirectory.
     */
    @Parameter(alias = "includes", defaultValue = "**")
    private String warSourceIncludes;

    /**
     * The comma separated list of tokens to exclude when copying the content
     * of the warSourceDirectory.
     */
    @Parameter(alias = "excludes")
    private String warSourceExcludes;

    /**
     * The comma separated list of tokens to include when doing
     * a WAR overlay.
     * Default is '**'
     *
     * @deprecated Use &lt;overlay&gt;/&lt;includes&gt; instead
     */
    @Parameter
    private String dependentWarIncludes = "**/**";

    /**
     * The comma separated list of tokens to exclude when doing
     * a WAR overlay.
     *
     * @deprecated Use &lt;overlay&gt;/&lt;excludes&gt; instead
     */
    @Parameter
    private String dependentWarExcludes = "META-INF/**";

    /**
     * The overlays to apply.
     *
     * Each &lt;overlay&gt; element may contain:
     * <ul>
     *     <li>id (defaults to <tt>currentBuild</tt>)</li>
     *     <li>groupId (if this and artifactId are null, then the current project is treated as its own overlay)</li>
     *     <li>artifactId (see above)</li>
     *     <li>classifier</li>
     *     <li>type</li>
     *     <li>includes (a list of string patterns)</li>
     *     <li>excludes (a list of string patterns)</li>
     *     <li>filtered (defaults to false)</li>
     *     <li>skip (defaults to false)</li>
     *     <li>targetPath (defaults to root of webapp structure)</li>
     *
     * </ul>
     *
     *
     *
     * @since 2.1-alpha-1
     */
    @Parameter
    private List<Overlay> overlays = new ArrayList<Overlay>();

    /**
     * A list of file extensions that should not be filtered.
     * <b>Will be used when filtering webResources and overlays.</b>
     *
     * @since 2.1-alpha-2
     */
    @Parameter
    private List<String> nonFilteredFileExtensions;

    /**
     * @since 2.1-alpha-2
     */
    @Component
    private MavenSession session;

    /**
     * To filter deployment descriptors. <b>Disabled by default.</b>
     *
     * @since 2.1-alpha-2
     */
    @Parameter(property = "maven.war.filteringDeploymentDescriptors", defaultValue = "false")
    private boolean filteringDeploymentDescriptors = false;

    /**
     * To escape interpolated values with Windows path
     * <code>c:\foo\bar</code> will be replaced with <code>c:\\foo\\bar</code>.
     *
     * @since 2.1-alpha-2
     */
    @Parameter(property = "maven.war.escapedBackslashesInFilePath", defaultValue = "false")
    private boolean escapedBackslashesInFilePath = false;

    /**
     * Expression preceded with this String won't be interpolated.
     * <code>\${foo}</code> will be replaced with <code>${foo}</code>.
     *
     * @since 2.1-beta-1
     */
    @Parameter(property = "maven.war.escapeString")
    protected String escapeString;

    /**
     * Indicates if zip archives (jar,zip etc) being added to the war should be
     * compressed again. Compressing again can result in smaller archive size, but
     * gives noticeably longer execution time.
     *
     * @since 2.3
     */
    @Parameter(defaultValue = "false")
    private boolean recompressZippedFiles;

    /**
     * The archive configuration to use.
     * See <a href="http://maven.apache.org/shared/maven-archiver/index.html">Maven Archiver Reference</a>.
     */
    @Parameter
    private MavenArchiveConfiguration archive = new MavenArchiveConfiguration();

    private final WebappStructureSerializer webappStructureSerialier = new WebappStructureSerializer();

    private final Overlay currentProjectOverlay = Overlay.createInstance();

    public Overlay getCurrentProjectOverlay() {
        return currentProjectOverlay;
    }

    /**
     * Returns a string array of the excludes to be used
     * when copying the content of the WAR source directory.
     *
     * @return an array of tokens to exclude
     */
    protected String[] getExcludes() {
        List<String> excludeList = new ArrayList<String>();
        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 WAR 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), ",");
    }

    public void buildExplodedWebapp(File webappDirectory) throws MojoExecutionException, MojoFailureException {
        webappDirectory.mkdirs();

        try {
            buildWebapp(project, webappDirectory);
        } catch (IOException e) {
            throw new MojoExecutionException("Could not build webapp", e);
        }
    }

    /**
     * Builds the webapp for the specified project with the new packaging task
     * thingy
     * <p/>
     * Classes, libraries and tld files are copied to
     * the <tt>webappDirectory</tt> during this phase.
     *
     * @param project         the maven project
     * @param webappDirectory the target directory
     * @throws org.apache.maven.plugin.MojoExecutionException if an error occurred while packaging the webapp
     * @throws org.apache.maven.plugin.MojoFailureException   if an unexpected error occurred while packaging the webapp
     * @throws java.io.IOException            if an error occurred while copying the files
     */
    @SuppressWarnings("unchecked")
    public void buildWebapp(MavenProject project, File webappDirectory)
            throws MojoExecutionException, MojoFailureException, IOException {

        WebappStructure cache;
        if (useCache && cacheFile.exists()) {
            cache = new WebappStructure(project.getDependencies(), webappStructureSerialier.fromXml(cacheFile));
        } else {
            cache = new WebappStructure(project.getDependencies(), null);
        }

        final long startTime = System.currentTimeMillis();
        getLog().info("Assembling webapp [" + project.getArtifactId() + "] in [" + webappDirectory + "]");

        final OverlayManager overlayManager = new OverlayManager(overlays, project, dependentWarIncludes,
                dependentWarExcludes, currentProjectOverlay);
        final List<WarPackagingTask> packagingTasks = getPackagingTasks(overlayManager);
        List<FileUtils.FilterWrapper> defaultFilterWrappers = null;
        try {
            MavenResourcesExecution mavenResourcesExecution = new MavenResourcesExecution();
            mavenResourcesExecution.setEscapeString(escapeString);

            defaultFilterWrappers = mavenFileFilter.getDefaultFilterWrappers(project, filters,
                    escapedBackslashesInFilePath, this.session, mavenResourcesExecution);

        } catch (MavenFilteringException e) {
            getLog().error("fail to build filering wrappers " + e.getMessage());
            throw new MojoExecutionException(e.getMessage(), e);
        }

        final WarPackagingContext context = new DefaultWarPackagingContext(webappDirectory, cache, overlayManager,
                defaultFilterWrappers, getNonFilteredFileExtensions(), filteringDeploymentDescriptors,
                this.artifactFactory, resourceEncoding);
        for (WarPackagingTask warPackagingTask : packagingTasks) {
            warPackagingTask.performPackaging(context);
        }

        // Post packaging
        final List<WarPostPackagingTask> postPackagingTasks = getPostPackagingTasks();
        for (WarPostPackagingTask task : postPackagingTasks) {
            task.performPostPackaging(context);
        }
        getLog().info("Webapp assembled in [" + (System.currentTimeMillis() - startTime) + " msecs]");

    }

    /**
     * Returns a <tt>List</tt> of the {@link org.piraso.maven.packaging.WarPackagingTask}
     * instances to invoke to perform the packaging.
     *
     * @param overlayManager the overlay manager
     * @return the list of packaging tasks
     * @throws org.apache.maven.plugin.MojoExecutionException if the packaging tasks could not be built
     */
    private List<WarPackagingTask> getPackagingTasks(OverlayManager overlayManager) throws MojoExecutionException {
        final List<WarPackagingTask> packagingTasks = new ArrayList<WarPackagingTask>();
        if (useCache) {
            packagingTasks.add(new DependenciesAnalysisPackagingTask());
        }

        final List<Overlay> resolvedOverlays = overlayManager.getOverlays();
        for (Overlay overlay : resolvedOverlays) {
            if (overlay.isCurrentProject()) {
                packagingTasks.add(new WarProjectPackagingTask(webResources, webXml, containerConfigXML,
                        currentProjectOverlay));
            } else {
                packagingTasks.add(new OverlayPackagingTask(overlay, currentProjectOverlay));
            }
        }
        return packagingTasks;
    }

    /**
     * Returns a <tt>List</tt> of the {@link org.piraso.maven.packaging.WarPostPackagingTask}
     * instances to invoke to perform the post-packaging.
     *
     * @return the list of post packaging tasks
     */
    private List<WarPostPackagingTask> getPostPackagingTasks() {
        final List<WarPostPackagingTask> postPackagingTasks = new ArrayList<WarPostPackagingTask>();
        if (useCache) {
            postPackagingTasks.add(new SaveWebappStructurePostPackagingTask(cacheFile));
        }
        // TODO add lib scanning to detect duplicates
        return postPackagingTasks;
    }

    /**
     * WarPackagingContext default implementation
     */
    private class DefaultWarPackagingContext implements WarPackagingContext {

        private final ArtifactFactory artifactFactory;

        private final String resourceEncoding;

        private final WebappStructure webappStructure;

        private final File webappDirectory;

        private final OverlayManager overlayManager;

        private final List<FileUtils.FilterWrapper> filterWrappers;

        private List<String> nonFilteredFileExtensions;

        private boolean filteringDeploymentDescriptors;

        public DefaultWarPackagingContext(File webappDirectory, final WebappStructure webappStructure,
                final OverlayManager overlayManager, List<FileUtils.FilterWrapper> filterWrappers,
                List<String> nonFilteredFileExtensions, boolean filteringDeploymentDescriptors,
                ArtifactFactory artifactFactory, String resourceEncoding) {
            this.webappDirectory = webappDirectory;
            this.webappStructure = webappStructure;
            this.overlayManager = overlayManager;
            this.filterWrappers = filterWrappers;
            this.artifactFactory = artifactFactory;
            this.filteringDeploymentDescriptors = filteringDeploymentDescriptors;
            this.nonFilteredFileExtensions = nonFilteredFileExtensions == null ? Collections.<String>emptyList()
                    : nonFilteredFileExtensions;
            this.resourceEncoding = resourceEncoding;
            // This is kinda stupid but if we loop over the current overlays and we request the path structure
            // it will register it. This will avoid wrong warning messages in a later phase
            for (String overlayId : overlayManager.getOverlayIds()) {
                webappStructure.getStructure(overlayId);
            }
        }

        public MavenProject getProject() {
            return project;
        }

        public File getWebappDirectory() {
            return webappDirectory;
        }

        public File getClassesDirectory() {
            return classesDirectory;
        }

        public Log getLog() {
            return AbstractWarMojo.this.getLog();
        }

        public String getOutputFileNameMapping() {
            return outputFileNameMapping;
        }

        public File getWebappSourceDirectory() {
            return warSourceDirectory;
        }

        public String[] getWebappSourceIncludes() {
            return getIncludes();
        }

        public String[] getWebappSourceExcludes() {
            return getExcludes();
        }

        public boolean archiveClasses() {
            return archiveClasses;
        }

        public File getOverlaysWorkDirectory() {
            return workDirectory;
        }

        public ArchiverManager getArchiverManager() {
            return archiverManager;
        }

        public MavenArchiveConfiguration getArchive() {
            return archive;
        }

        public JarArchiver getJarArchiver() {
            return jarArchiver;
        }

        public List<String> getFilters() {
            return filters;
        }

        public WebappStructure getWebappStructure() {
            return webappStructure;
        }

        public List<String> getOwnerIds() {
            return overlayManager.getOverlayIds();
        }

        public MavenFileFilter getMavenFileFilter() {
            return mavenFileFilter;
        }

        public List<FileUtils.FilterWrapper> getFilterWrappers() {
            return filterWrappers;
        }

        public boolean isNonFilteredExtension(String fileName) {
            return !mavenResourcesFiltering.filteredFileExtension(fileName, nonFilteredFileExtensions);
        }

        public boolean isFilteringDeploymentDescriptors() {
            return filteringDeploymentDescriptors;
        }

        public ArtifactFactory getArtifactFactory() {
            return this.artifactFactory;
        }

        public MavenSession getSession() {
            return session;
        }

        public String getResourceEncoding() {
            return resourceEncoding;
        }
    }

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

    public String getOutputFileNameMapping() {
        return outputFileNameMapping;
    }

    public void setOutputFileNameMapping(String outputFileNameMapping) {
        this.outputFileNameMapping = outputFileNameMapping;
    }

    public List<Overlay> getOverlays() {
        return overlays;
    }

    public void setOverlays(List<Overlay> overlays) {
        this.overlays = overlays;
    }

    public void addOverlay(Overlay overlay) {
        overlays.add(overlay);
    }

    public boolean isArchiveClasses() {
        return archiveClasses;
    }

    public void setArchiveClasses(boolean archiveClasses) {
        this.archiveClasses = archiveClasses;
    }

    public JarArchiver getJarArchiver() {
        return jarArchiver;
    }

    public void setJarArchiver(JarArchiver jarArchiver) {
        this.jarArchiver = jarArchiver;
    }

    public Resource[] getWebResources() {
        return webResources;
    }

    public void setWebResources(Resource[] webResources) {
        this.webResources = webResources;
    }

    public List<String> getFilters() {
        return filters;
    }

    public void setFilters(List<String> filters) {
        this.filters = filters;
    }

    public File getWorkDirectory() {
        return workDirectory;
    }

    public void setWorkDirectory(File workDirectory) {
        this.workDirectory = workDirectory;
    }

    public File getCacheFile() {
        return cacheFile;
    }

    public void setCacheFile(File cacheFile) {
        this.cacheFile = cacheFile;
    }

    public String getWarSourceIncludes() {
        return warSourceIncludes;
    }

    public void setWarSourceIncludes(String warSourceIncludes) {
        this.warSourceIncludes = warSourceIncludes;
    }

    public String getWarSourceExcludes() {
        return warSourceExcludes;
    }

    public void setWarSourceExcludes(String warSourceExcludes) {
        this.warSourceExcludes = warSourceExcludes;
    }

    public boolean isUseCache() {
        return useCache;
    }

    public void setUseCache(boolean useCache) {
        this.useCache = useCache;
    }

    public MavenArchiveConfiguration getArchive() {
        return archive;
    }

    public List<String> getNonFilteredFileExtensions() {
        return nonFilteredFileExtensions;
    }

    public void setNonFilteredFileExtensions(List<String> nonFilteredFileExtensions) {
        this.nonFilteredFileExtensions = nonFilteredFileExtensions;
    }

    public ArtifactFactory getArtifactFactory() {
        return this.artifactFactory;
    }

    public void setArtifactFactory(ArtifactFactory artifactFactory) {
        this.artifactFactory = artifactFactory;
    }

    protected MavenSession getSession() {
        return this.session;
    }

    protected boolean isRecompressZippedFiles() {
        return recompressZippedFiles;
    }
}