All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.wanghaomiao.maven.plugin.seimi.packaging.AbstractWarPackagingTask Maven / Gradle / Ivy

package cn.wanghaomiao.maven.plugin.seimi.packaging;

/*
 * 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 cn.wanghaomiao.maven.plugin.seimi.util.PathSet;
import org.apache.commons.io.input.XmlStreamReader;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.MojoExecutionException;
import cn.wanghaomiao.maven.plugin.seimi.util.WebappStructure;
import org.apache.maven.shared.filtering.MavenFilteringException;
import org.apache.maven.shared.mapping.MappingUtils;
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.NoSuchArchiverException;
import org.codehaus.plexus.interpolation.InterpolationException;
import org.codehaus.plexus.util.DirectoryScanner;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.IOUtil;

/**
 * @author Stephane Nicoll
 * @version $Id: AbstractWarPackagingTask.java 1637197 2014-11-06 19:46:57Z khmarbaise $
 */
public abstract class AbstractWarPackagingTask
    implements WarPackagingTask
{
    /**
     * The default list of includes.
     */
    public static final String[] DEFAULT_INCLUDES = { "**/**" };

    /**
     * The {@code WEB-INF} path.
     */
    public static final String WEB_INF_PATH = "seimi";

    /**
     * The {@code META-INF} path.
     */
    public static final String META_INF_PATH = "seimi";

    /**
     * The {@code classes} path.
     */
    public static final String CLASSES_PATH = "seimi/classes/";

    /**
     * The {@code lib} path.
     */
    public static final String LIB_PATH = "seimi/lib/";

    /**
     * Copies the files if possible with an optional target prefix.
     * 

* Copy uses a first-win strategy: files that have already been copied by previous tasks are ignored. This method * makes sure to update the list of protected files which gives the list of files that have already been copied. *

* If the structure of the source directory is not the same as the root of the webapp, use the targetPrefix * parameter to specify in which particular directory the files should be copied. Use null to copy the * files with the same structure * * @param sourceId the source id * @param context the context to use * @param sourceBaseDir the base directory from which the sourceFilesSet will be copied * @param sourceFilesSet the files to be copied * @param targetPrefix the prefix to add to the target file name * @param filtered filter or not. * @throws IOException if an error occurred while copying the files * @throws MojoExecutionException if an error occurs. */ protected void copyFiles( String sourceId, WarPackagingContext context, File sourceBaseDir, PathSet sourceFilesSet, String targetPrefix, boolean filtered ) throws IOException, MojoExecutionException { for ( String fileToCopyName : sourceFilesSet.paths() ) { final File sourceFile = new File( sourceBaseDir, fileToCopyName ); String destinationFileName; if ( targetPrefix == null ) { destinationFileName = fileToCopyName; } else { destinationFileName = targetPrefix + fileToCopyName; } if ( filtered && !context.isNonFilteredExtension( sourceFile.getName() ) ) { copyFilteredFile( sourceId, context, sourceFile, destinationFileName ); } else { copyFile( sourceId, context, sourceFile, destinationFileName ); } } } /** * Copies the files if possible as is. *

* Copy uses a first-win strategy: files that have already been copied by previous tasks are ignored. This method * makes sure to update the list of protected files which gives the list of files that have already been copied. * * @param sourceId the source id * @param context the context to use * @param sourceBaseDir the base directory from which the sourceFilesSet will be copied * @param sourceFilesSet the files to be copied * @param filtered filter or not. * @throws IOException if an error occurred while copying the files * @throws MojoExecutionException break the build. */ protected void copyFiles( String sourceId, WarPackagingContext context, File sourceBaseDir, PathSet sourceFilesSet, boolean filtered ) throws IOException, MojoExecutionException { copyFiles( sourceId, context, sourceBaseDir, sourceFilesSet, null, filtered ); } /** * Copy the specified file if the target location has not yet already been used. *

* The targetFileName is the relative path according to the root of the generated web application. * * @param sourceId the source id * @param context the context to use * @param file the file to copy * @param targetFilename the relative path according to the root of the webapp * @throws IOException if an error occurred while copying */ // CHECKSTYLE_OFF: LineLength protected void copyFile( String sourceId, final WarPackagingContext context, final File file, String targetFilename ) throws IOException // CHECKSTYLE_ON: LineLength { final File targetFile = new File( context.getWebappDirectory(), targetFilename ); if ( file.isFile() ) { context.getWebappStructure().registerFile( sourceId, targetFilename, new WebappStructure.RegistrationCallback() { public void registered( String ownerId, String targetFilename ) throws IOException { copyFile( context, file, targetFile, targetFilename, false ); } public void alreadyRegistered( String ownerId, String targetFilename ) throws IOException { copyFile( context, file, targetFile, targetFilename, true ); } public void refused( String ownerId, String targetFilename, String actualOwnerId ) throws IOException { context.getLog().debug( " - " + targetFilename + " wasn't copied because it has " + "already been packaged for overlay [" + actualOwnerId + "]." ); } public void superseded( String ownerId, String targetFilename, String deprecatedOwnerId ) throws IOException { context.getLog().info( "File [" + targetFilename + "] belonged to overlay [" + deprecatedOwnerId + "] so it will be overwritten." ); copyFile( context, file, targetFile, targetFilename, false ); } public void supersededUnknownOwner( String ownerId, String targetFilename, String unknownOwnerId ) throws IOException { // CHECKSTYLE_OFF: LineLength context.getLog().warn( "File [" + targetFilename + "] belonged to overlay [" + unknownOwnerId + "] which does not exist anymore in the current project. It is recommended to invoke " + "clean if the dependencies of the project changed." ); // CHECKSTYLE_ON: LineLength copyFile( context, file, targetFile, targetFilename, false ); } } ); } else if ( !targetFile.exists() && !targetFile.mkdirs() ) { context.getLog().info( "Failed to create directory " + targetFile.getAbsolutePath() ); } } /** * Copy the specified file if the target location has not yet already been used and filter its content with the * configured filter properties. *

* The targetFileName is the relative path according to the root of the generated web application. * * @param sourceId the source id * @param context the context to use * @param file the file to copy * @param targetFilename the relative path according to the root of the webapp * @return true if the file has been copied, false otherwise * @throws IOException if an error occurred while copying * @throws MojoExecutionException if an error occurred while retrieving the filter properties */ protected boolean copyFilteredFile( String sourceId, final WarPackagingContext context, File file, String targetFilename ) throws IOException, MojoExecutionException { if ( context.getWebappStructure().registerFile( sourceId, targetFilename ) ) { final File targetFile = new File( context.getWebappDirectory(), targetFilename ); final String encoding; try { if ( isXmlFile( file ) ) { // For xml-files we extract the encoding from the files encoding = getEncoding( file ); } else { // For all others we use the configured encoding encoding = context.getResourceEncoding(); } // fix for MWAR-36, ensures that the parent dir are created first targetFile.getParentFile().mkdirs(); context.getMavenFileFilter().copyFile( file, targetFile, true, context.getFilterWrappers(), encoding ); } catch ( MavenFilteringException e ) { throw new MojoExecutionException( e.getMessage(), e ); } // CHECKSTYLE_OFF: LineLength // Add the file to the protected list context.getLog().debug( " + " + targetFilename + " has been copied (filtered encoding='" + encoding + "')." ); // CHECKSTYLE_ON: LineLength return true; } else { context.getLog().debug( " - " + targetFilename + " wasn't copied because it has already been packaged (filtered)." ); return false; } } /** * Unpacks the specified file to the specified directory. * * @param context the packaging context * @param file the file to unpack * @param unpackDirectory the directory to use for th unpacked file * @throws MojoExecutionException if an error occurred while unpacking the file */ protected void doUnpack( WarPackagingContext context, File file, File unpackDirectory ) throws MojoExecutionException { String archiveExt = FileUtils.getExtension( file.getAbsolutePath() ).toLowerCase(); try { UnArchiver unArchiver = context.getArchiverManager().getUnArchiver( archiveExt ); unArchiver.setSourceFile( file ); unArchiver.setUseJvmChmod( context.isUseJvmChmod() ); unArchiver.setDestDirectory( unpackDirectory ); unArchiver.setOverwrite( true ); unArchiver.extract(); } catch ( ArchiverException e ) { throw new MojoExecutionException( "Error unpacking file [" + file.getAbsolutePath() + "]" + "to [" + unpackDirectory.getAbsolutePath() + "]", e ); } catch ( NoSuchArchiverException e ) { context.getLog().warn( "Skip unpacking dependency file [" + file.getAbsolutePath() + " with unknown extension [" + archiveExt + "]" ); } } /** * Copy file from source to destination. The directories up to destination will be created if they * don't already exist. if the onlyIfModified flag is false, destination will be * overwritten if it already exists. If the flag is true destination will be overwritten if it's not up to * date. *

* * @param context the packaging context * @param source an existing non-directory File to copy bytes from * @param destination a non-directory File to write bytes to (possibly overwriting). * @param targetFilename the relative path of the file from the webapp root directory * @param onlyIfModified if true, copy the file only if the source has changed, always copy otherwise * @return true if the file has been copied/updated, false otherwise * @throws IOException if source does not exist, destination cannot be written to, or an * IO error occurs during copying */ protected boolean copyFile( WarPackagingContext context, File source, File destination, String targetFilename, boolean onlyIfModified ) throws IOException { if ( onlyIfModified && destination.lastModified() >= source.lastModified() ) { context.getLog().debug( " * " + targetFilename + " is up to date." ); return false; } else { if ( source.isDirectory() ) { context.getLog().warn( " + " + targetFilename + " is packaged from the source folder" ); try { JarArchiver archiver = context.getJarArchiver(); archiver.addDirectory( source ); archiver.setDestFile( destination ); archiver.createArchive(); } catch ( ArchiverException e ) { String msg = "Failed to create " + targetFilename; context.getLog().error( msg, e ); IOException ioe = new IOException( msg ); ioe.initCause( e ); throw ioe; } } else { FileUtils.copyFile( source.getCanonicalFile(), destination ); // preserve timestamp destination.setLastModified( source.lastModified() ); context.getLog().debug( " + " + targetFilename + " has been copied." ); } return true; } } /** * Get the encoding from an XML-file. * * @param webXml the XML-file * @return The encoding of the XML-file, or UTF-8 if it's not specified in the file * @throws java.io.IOException if an error occurred while reading the file */ protected String getEncoding( File webXml ) throws IOException { XmlStreamReader xmlReader = new XmlStreamReader( webXml ); try { return xmlReader.getEncoding(); } finally { IOUtil.close( xmlReader ); } } /** * Returns the file to copy. If the includes are null or empty, the default includes are used. * * @param baseDir the base directory to start from * @param includes the includes * @param excludes the excludes * @return the files to copy */ protected PathSet getFilesToIncludes( File baseDir, String[] includes, String[] excludes ) { return getFilesToIncludes( baseDir, includes, excludes, false ); } /** * Returns the file to copy. If the includes are null or empty, the default includes are used. * * @param baseDir the base directory to start from * @param includes the includes * @param excludes the excludes * @param includeDirectories include directories yes or not. * @return the files to copy */ // CHECKSTYLE_OFF: LineLength protected PathSet getFilesToIncludes( File baseDir, String[] includes, String[] excludes, boolean includeDirectories ) // CHECKSTYLE_ON: LineLength { final DirectoryScanner scanner = new DirectoryScanner(); scanner.setBasedir( baseDir ); if ( excludes != null ) { scanner.setExcludes( excludes ); } scanner.addDefaultExcludes(); if ( includes != null && includes.length > 0 ) { scanner.setIncludes( includes ); } else { scanner.setIncludes( DEFAULT_INCLUDES ); } scanner.scan(); PathSet pathSet = new PathSet( scanner.getIncludedFiles() ); if ( includeDirectories ) { pathSet.addAll( scanner.getIncludedDirectories() ); } return pathSet; } /** * Returns the final name of the specified artifact. *

* If the outputFileNameMapping is set, it is used, otherwise the standard naming scheme is used. * * @param context the packaging context * @param artifact the artifact * @return the converted filename of the artifact * @throws InterpolationException in case of interpolation problem. */ protected String getArtifactFinalName( WarPackagingContext context, Artifact artifact ) throws InterpolationException { if ( context.getOutputFileNameMapping() != null ) { return MappingUtils.evaluateFileNameMapping( context.getOutputFileNameMapping(), artifact ); } String classifier = artifact.getClassifier(); if ( ( classifier != null ) && !( "".equals( classifier.trim() ) ) ) { return MappingUtils.evaluateFileNameMapping( MappingUtils.DEFAULT_FILE_NAME_MAPPING_CLASSIFIER, artifact ); } else { return MappingUtils.evaluateFileNameMapping( MappingUtils.DEFAULT_FILE_NAME_MAPPING, artifact ); } } /** * Returns true if the File-object is a file (not a directory) that is not * null and has a file name that ends in ".xml". * * @param file The file to check * @return true if the file is an xml-file, otherwise false * @since 2.3 */ private boolean isXmlFile( File file ) { return file != null && file.isFile() && file.getName().endsWith( ".xml" ); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy