Java Network Launching Protocol (JNLP,java网络加载协议)。
一般情况下Maven打成的War包路径如下
Web/
/WEB-INF/
/*.jsp
/WEB-INF/web.xml
/WEB-INF/lib/*.jar
这里有一个问题JNLP指向的jar包必须位于WEB-INF之外,而Maven打成的包后jar全部位于/WEB-INF/lib,因此必须想办法让Maven将
jar放置到WEB-INF的外面,通过扩展Maven的插件能做到。
1.下载源码 http://repo1.maven.org/maven2/org/apache/maven/plugins/maven-war-plugin/
2. 修改代码 WarMojo.java
package org.apache.maven.plugin.war;
/*
* 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.MavenArchiver;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DependencyResolutionRequiredException;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.war.util.ClassesPackager;
import org.apache.maven.project.MavenProjectHelper;
import org.codehaus.plexus.archiver.ArchiverException;
import org.codehaus.plexus.archiver.jar.ManifestException;
import org.codehaus.plexus.archiver.war.WarArchiver;
import org.codehaus.plexus.util.StringUtils;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
/**
* Build a WAR file.
*
* @author <a href="evenisse@apache.org">Emmanuel Venisse</a>
* @version $Id: WarMojo.java 751466 2009-03-08 16:34:06Z dennisl $
* @goal war
* @phase package
* @requiresDependencyResolution runtime
*/
public class WarMojo
extends AbstractWarMojo
{
/**
* The directory for the generated WAR.
*
* @parameter expression="${project.build.directory}"
* @required
*/
private String outputDirectory;
/**
* The name of the generated WAR.
*
* @parameter expression="${project.build.finalName}"
* @required
*/
private String warName;
/**
* Classifier to add to the generated WAR. If given, the artifact will be an attachment instead.
* The classifier will not be applied to the jar file of the project - only to the war file.
*
* @parameter
*/
private String classifier;
/**
* The comma separated list of tokens to exclude from the WAR before
* packaging. This option may be used to implement the skinny war use
* case.
*
* @parameter alias="packagingExcludes"
* @since 2.1-alpha-2
*/
private String packagingExcludes;
/**
* The comma separated list of tokens to include in the WAR before
* packaging. By default everything is included. This option may be used
* to implement the skinny war use case.
*
* @parameter alias="packagingIncludes"
* @since 2.1-beta-1
*/
private String packagingIncludes;
/**
* The War archiver.
*
* @component role="org.codehaus.plexus.archiver.Archiver" roleHint="war"
*/
private WarArchiver warArchiver;
/**
* @component
*/
private MavenProjectHelper projectHelper;
/**
* Whether this is the main artifact being built. Set to <code>false</code> if you don't want to install or
* deploy it to the local repository instead of the default one in an execution.
*
* @parameter expression="${primaryArtifact}" default-value="true"
*/
private boolean primaryArtifact = true;
/**
* Whether or not to fail the build is the <code>web.xml</code> file is missing. Set to <code>false</code>
* if you want you war built without a <code>web.xml</code> file.
*
* @parameter expression="${failOnMissingWebXml}" default-value="true"
* @since 2.1-alpha-2
*/
private boolean failOnMissingWebXml = true;
/**
* Whether classes (that is the content of the WEB-INF/classes directory) should be attached to the
* project.
*
* @parameter default-value="false"
* @since 2.1-alpha-2
*/
private boolean attachClasses = false;
/**
* The classifier to use for the attached classes artifact.
*
* @parameter default-value="classes"
* @since 2.1-alpha-2
*/
private String classesClassifier = "classes";
// ----------------------------------------------------------------------
// Implementation
// ----------------------------------------------------------------------
/**
* Executes the WarMojo on the current project.
*
* @throws MojoExecutionException if an error occurred while building the webapp
*/
public void execute()
throws MojoExecutionException, MojoFailureException
{
File warFile = getTargetWarFile();
try
{
performPackaging( warFile );
}
catch ( DependencyResolutionRequiredException e )
{
throw new MojoExecutionException( "Error assembling WAR: " + e.getMessage(), e );
}
catch ( ManifestException e )
{
throw new MojoExecutionException( "Error assembling WAR", e );
}
catch ( IOException e )
{
throw new MojoExecutionException( "Error assembling WAR", e );
}
catch ( ArchiverException e )
{
throw new MojoExecutionException( "Error assembling WAR: " + e.getMessage(), e );
}
}
/**
* Generates the webapp according to the <tt>mode</tt> attribute.
*
* @param warFile the target war file
* @throws IOException if an error occurred while copying files
* @throws ArchiverException if the archive could not be created
* @throws ManifestException if the manifest could not be created
* @throws DependencyResolutionRequiredException
* if an error occurred while resolving the dependencies
* @throws MojoExecutionException if the execution failed
* @throws MojoFailureException if a fatal exception occurred
*/
private void performPackaging( File warFile )
throws IOException, ArchiverException, ManifestException, DependencyResolutionRequiredException,
MojoExecutionException, MojoFailureException
{
getLog().info( "Packaging webapp" );
buildExplodedWebapp( getWebappDirectory() );
jarLibs();
MavenArchiver archiver = new MavenArchiver();
archiver.setArchiver( warArchiver );
archiver.setOutputFile( warFile );
getLog().debug(
"Excluding " + Arrays.asList( getPackagingExcludes() ) + " from the generated webapp archive." );
getLog().debug(
"Including " + Arrays.asList( getPackagingIncludes() ) + " in the generated webapp archive." );
warArchiver.addDirectory( getWebappDirectory(), getPackagingIncludes(), getPackagingExcludes() );
final File webXmlFile = new File( getWebappDirectory(), "WEB-INF/web.xml" );
if ( webXmlFile.exists() )
{
warArchiver.setWebxml( webXmlFile );
}
if ( !failOnMissingWebXml )
{
getLog().debug( "Build won't fail if web.xml file is missing." );
// The flag is wrong in plexus-archiver so it will need to be fixed at some point
warArchiver.setIgnoreWebxml( false );
}
// create archive
archiver.createArchive( getProject(), getArchive() );
// create the classes to be attached if necessary
if ( isAttachClasses() )
{
ClassesPackager packager = new ClassesPackager();
final File classesDirectory = packager.getClassesDirectory( getWebappDirectory() );
if ( classesDirectory.exists() )
{
getLog().info( "Packaging classes" );
packager.packageClasses( classesDirectory, getTargetClassesFile(), getJarArchiver(), getProject(),
getArchive() );
projectHelper.attachArtifact( getProject(), "jar", getClassesClassifier(), getTargetClassesFile() );
}
}
String classifier = this.classifier;
if ( classifier != null )
{
projectHelper.attachArtifact( getProject(), "war", classifier, warFile );
}
else
{
Artifact artifact = getProject().getArtifact();
if ( primaryArtifact )
{
artifact.setFile( warFile );
}
else if ( artifact.getFile() == null || artifact.getFile().isDirectory() )
{
artifact.setFile( warFile );
}
}
}
protected static File getTargetFile( File basedir, String finalName, String classifier, String type )
{
if ( classifier == null )
{
classifier = "";
}
else if ( classifier.trim().length() > 0 && !classifier.startsWith( "-" ) )
{
classifier = "-" + classifier;
}
return new File( basedir, finalName + classifier + "." + type );
}
protected File getTargetWarFile()
{
return getTargetFile( new File( getOutputDirectory() ), getWarName(), getClassifier(), "war" );
}
protected File getTargetClassesFile()
{
return getTargetFile( new File( getOutputDirectory() ), getWarName(), getClassesClassifier(), "jar" );
}
// Getters and Setters
public String getClassifier()
{
return classifier;
}
public void setClassifier( String classifier )
{
this.classifier = classifier;
}
public String[] getPackagingExcludes()
{
if ( StringUtils.isEmpty( packagingExcludes ) )
{
return new String[0];
}
else
{
return StringUtils.split( packagingExcludes, "," );
}
}
public void setPackagingExcludes( String packagingExcludes )
{
this.packagingExcludes = packagingExcludes;
}
public String[] getPackagingIncludes()
{
if ( StringUtils.isEmpty( packagingIncludes ) )
{
return new String[]{"**"};
}
else
{
return StringUtils.split( packagingIncludes, "," );
}
}
public void setPackagingIncludes( String packagingIncludes )
{
this.packagingIncludes = packagingIncludes;
}
public String getOutputDirectory()
{
return outputDirectory;
}
public void setOutputDirectory( String outputDirectory )
{
this.outputDirectory = outputDirectory;
}
public String getWarName()
{
return warName;
}
public void setWarName( String warName )
{
this.warName = warName;
}
public WarArchiver getWarArchiver()
{
return warArchiver;
}
public void setWarArchiver( WarArchiver warArchiver )
{
this.warArchiver = warArchiver;
}
public MavenProjectHelper getProjectHelper()
{
return projectHelper;
}
public void setProjectHelper( MavenProjectHelper projectHelper )
{
this.projectHelper = projectHelper;
}
public boolean isPrimaryArtifact()
{
return primaryArtifact;
}
public void setPrimaryArtifact( boolean primaryArtifact )
{
this.primaryArtifact = primaryArtifact;
}
public boolean isAttachClasses()
{
return attachClasses;
}
public void setAttachClasses( boolean attachClasses )
{
this.attachClasses = attachClasses;
}
public String getClassesClassifier()
{
return classesClassifier;
}
public void setClassesClassifier( String classesClassifier )
{
this.classesClassifier = classesClassifier;
}
public boolean isFailOnMissingWebXml()
{
return failOnMissingWebXml;
}
public void setFailOnMissingWebXml( boolean failOnMissingWebXml )
{
this.failOnMissingWebXml = failOnMissingWebXml;
}
}
3. 修改WarPackagingContext.java
package org.apache.maven.plugin.war.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.util.List;
import org.apache.maven.archiver.MavenArchiveConfiguration;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.plugin.war.util.WebappStructure;
import org.apache.maven.project.MavenProject;
import org.apache.maven.shared.filtering.MavenFileFilter;
import org.codehaus.plexus.archiver.jar.JarArchiver;
import org.codehaus.plexus.archiver.manager.ArchiverManager;
import org.codehaus.plexus.util.FileUtils.FilterWrapper;
/**
* The packaging context.
*
* @author Stephane Nicoll
* @version $Id: WarPackagingContext.java 743374 2009-02-11 16:28:01Z dennisl $
*/
public interface WarPackagingContext
{
/**
* Returns the maven project.
*
* @return the project
*/
MavenProject getProject();
/**
* Returns the webapp directory. Packaging tasks should use this
* directory to generate the webapp.
*
* @return the webapp directory
*/
File getWebappDirectory();
/**
* Returns the main webapp source directory.
*
* @return the webapp source directory
*/
File getWebappSourceDirectory();
/**
* Returns the webapp source includes.
*
* @return the webapp source includes
*/
String[] getWebappSourceIncludes();
/**
* Returns the webapp source excludes.
*
* @return the webapp source excludes
*/
String[] getWebappSourceExcludes();
/**
* Returns the directory holding generated classes.
*
* @return the classes directory
*/
File getClassesDirectory();
/**
* Specify whether the classes resources should be archived in
* the <tt>WEB-INF/lib</tt> of the generated web app.
*
* @return true if the classes should be archived, false otherwise
*/
boolean archiveClasses();
/**
* Returns the logger to use to output logging event.
*
* @return the logger
*/
Log getLog();
/**
* Returns the directory to unpack dependent WARs into if needed.
*
* @return the overlays work directory
*/
File getOverlaysWorkDirectory();
/**
* Returns the archiver manager to use.
*
* @return the archiver manager
*/
ArchiverManager getArchiverManager();
/**
* The maven archive configuration to use.
*
* @return the maven archive configuration
*/
MavenArchiveConfiguration getArchive();
/**
* Returns the Jar archiver needed for archiving classes directory into
* jar file under WEB-INF/lib.
*
* @return the jar archiver to user
*/
JarArchiver getJarArchiver();
/**
* Returns the output file name mapping to use, if any. Returns <tt>null</tt>
* if no file name mapping is set.
*
* @return the output file name mapping or <tt>null</tt>
*/
String getOutputFileNameMapping();
/**
* Returns the list of filter files to use.
*
* @return a list of filter files
*/
List getFilters();
/**
* Returns the {@link WebappStructure}.
*
* @return the webapp structure
*/
WebappStructure getWebappStructure();
/**
* Returns the list of registered overlays for this session. This list might
* differ from the one returned by the cache; in this case, it means that the
* project's configuration has changed. The plugin will handle thos cases nicely
* but it would be better in general to invoke the clean goal.
*
* @return the list of registered overlays, including the current project
*/
List getOwnerIds();
/**
* Returns the {@link MavenFileFilter} instance to use.
*
* @return the maven file filter to use
* @since 2.1-alpha-2
*/
MavenFileFilter getMavenFileFilter();
/**
* @return {@link List} of {@link FilterWrapper}
* @since 2.1-alpha-2
*/
List getFilterWrappers();
/**
* Specify if the given <tt>fileName</tt> belongs to the list of extensions
* that must not be filtered
*
* @param fileName the name of file
* @return <tt>true</tt> if it should not be filtered, <tt>false</tt> otherwise
* @since 2.1-alpha-2
*/
boolean isNonFilteredExtension( String fileName );
boolean isFilteringDeploymentDescriptors();
ArtifactFactory getArtifactFactory();
//add by
String getLibRelativeWebappDirectory();
//add by
String getFilterLibs();
}
4. 修改AbstractWarMojo.java
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
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.plugin.war.overlay.OverlayManager;
import org.apache.maven.plugin.war.packaging.DependenciesAnalysisPackagingTask;
import org.apache.maven.plugin.war.packaging.OverlayPackagingTask;
import org.apache.maven.plugin.war.packaging.SaveWebappStructurePostPackagingTask;
import org.apache.maven.plugin.war.packaging.WarPackagingContext;
import org.apache.maven.plugin.war.packaging.WarPackagingTask;
import org.apache.maven.plugin.war.packaging.WarPostPackagingTask;
import org.apache.maven.plugin.war.packaging.WarProjectPackagingTask;
import org.apache.maven.plugin.war.util.WebappStructure;
import org.apache.maven.plugin.war.util.WebappStructureSerializer;
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.mojo.webstart.SignConfig;
import org.codehaus.mojo.webstart.JnlpMojo.KeystoreConfig;
import org.codehaus.plexus.archiver.jar.JarArchiver;
import org.codehaus.plexus.archiver.manager.ArchiverManager;
import org.codehaus.plexus.util.StringUtils;
/**
* Contains commons jobs for war mojos.
*
* @version $Id: AbstractWarMojo.java 751806 2009-03-09 19:44:08Z dennisl $
*/
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";
/**
* @parameter property="relativeLibPath"
*/
private String relativeLibPath;
/**
* @parameter
*/
private SignConfig sign;
/**
* keystore
*
* @parameter
*/
private KeystoreConfig keystore;
/**
* Enable verbose.
*
* @parameter expression="${verbose}" default-value="false"
*/
private boolean verbose;
/**
* @parameter default-valuel="false";
*/
private boolean isUseOutKeystore;
/**
* Filters artifactid jar
* @parameter
*/
private String filterLibs;
/**
* lib output directory
* @parameter
*/
private String libRelativeWebappDirectory;
/**
* The maven project.
*
* @parameter expression="${project}"
* @required
* @readonly
*/
private MavenProject project;
/**
* The directory containing generated classes.
*
* @parameter expression="${project.build.outputDirectory}"
* @required
* @readonly
*/
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 expression="${archiveClasses}" default-value="false"
* @since 2.0.1
*/
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" role-hint="jar"
* @required
*/
private JarArchiver jarArchiver;
/**
* The directory where the webapp is built.
*
* @parameter expression="${project.build.directory}/${project.build.finalName}"
* @required
*/
private File webappDirectory;
/**
* Single directory for extra files to include in the WAR.
*
* @parameter expression="${basedir}/src/main/webapp"
* @required
*/
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 filters;
/**
* The path to the web.xml file to use.
*
* @parameter expression="${maven.war.webxml}"
*/
private File webXml;
/**
* The path to the context.xml file to use.
*
* @parameter expression="${maven.war.containerConfigXML}"
*/
private File containerConfigXML;
/**
* Directory to unpack dependent WARs into if needed
*
* @parameter expression="${project.build.directory}/war/work"
* @required
*/
private File workDirectory;
/**
* The file name mapping to use to copy libraries and tlds. If no file mapping is
* set (default) the file is copied with its standard name.
*
* @parameter
* @since 2.1-alpha-1
*/
private String outputFileNameMapping;
/**
* The file containing the webapp structure cache.
*
* @parameter expression="${project.build.directory}/war/work/webapp-cache.xml"
* @required
* @since 2.1-alpha-1
*/
private File cacheFile;
/**
* Whether the cache should be used to save the status of the webapp
* accross multiple runs.
*
* @parameter expression="${useCache}" default-value="true"
* @since 2.1-alpha-1
*/
private boolean useCache = true;
/**
* @component role="org.apache.maven.artifact.factory.ArtifactFactory"
* @required
* @readonly
*/
private ArtifactFactory artifactFactory;
/**
* To look up Archiver/UnArchiver implementations
*
* @component role="org.codehaus.plexus.archiver.manager.ArchiverManager"
* @required
*/
private ArchiverManager archiverManager;
/**
*
* @component role="org.apache.maven.shared.filtering.MavenFileFilter" role-hint="default"
* @required
*/
private MavenFileFilter mavenFileFilter;
/**
*
* @component role="org.apache.maven.shared.filtering.MavenResourcesFiltering" role-hint="default"
* @required
*/
private MavenResourcesFiltering mavenResourcesFiltering;
/**
* The comma separated list of tokens to include when copying content
* of the warSourceDirectory. Default is '**'.
*
* @parameter alias="includes"
*/
private String warSourceIncludes = "**";
/**
* The comma separated list of tokens to exclude when copying 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 '**'
*
* @parameter
*
* @deprecated use the includes in the overlay object instead
*/
private String dependentWarIncludes = "**/**";
/**
* The comma separated list of tokens to exclude when doing
* a war overlay.
*
* @parameter
*
* @deprecated use the excludes in the overlay object instead
*/
private String dependentWarExcludes = "META-INF/**";
/**
* The overlays to apply.
*
* @parameter
* @since 2.1
*/
private List overlays = new ArrayList();
/**
* A list of file extensions to not filtering.
* <b>will be used for webResources and overlay filtering</b>
*
* @parameter
* @since 2.1-alpha-2
*/
private List nonFilteredFileExtensions;
/**
* @parameter expression="${session}"
* @readonly
* @required
* @since 2.1-alpha-2
*/
private MavenSession session;
/**
* To filtering deployment descriptors <b>disabled by default</b>
*
* @parameter expression="${maven.war.filteringDeploymentDescriptors}" default-value="false"
* @since 2.1-alpha-2
*/
private boolean filteringDeploymentDescriptors = false;
/**
* To escape interpolated value with windows path
* c:/foo/bar will be replaced with c://foo//bar
* @parameter expression="${maven.war.escapedBackslashesInFilePath}" default-value="false"
* @since 2.1-alpha-2
*/
private boolean escapedBackslashesInFilePath = false;
/**
* Expression preceded with the String won't be interpolated
* /${foo} will be replaced with ${foo}
* @parameter expression="${maven.war.escapeString}"
* @since 2.1-beta-1
*/
protected String escapeString;
/**
* 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();
/**
* 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 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 ), "," );
}
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 MojoExecutionException if an error occurred while packaging the webapp
* @throws MojoFailureException if an unexpected error occurred while packaging the webapp
* @throws IOException if an error occurred while copying the files
*/
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 );
final List packagingTasks = getPackagingTasks( overlayManager );
List 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 );
final Iterator it = packagingTasks.iterator();
while ( it.hasNext() )
{
WarPackagingTask warPackagingTask = (WarPackagingTask) it.next();
warPackagingTask.performPackaging( context );
}
// Post packaging
final List postPackagingTasks = getPostPackagingTasks();
final Iterator it2 = postPackagingTasks.iterator();
while ( it2.hasNext() )
{
WarPostPackagingTask task = (WarPostPackagingTask) it2.next();
task.performPostPackaging( context );
}
getLog().info( "Webapp assembled in [" + ( System.currentTimeMillis() - startTime ) + " msecs]" );
}
public void jarLibs()
{
JarSign jarSign = new JarSign();
jarSign.setWorkDirectory(webappDirectory);
jarSign.setVerbose(verbose);
jarSign.setSign(sign);
jarSign.setRelativeLibPath(relativeLibPath);
jarSign.setKeystore(keystore);
jarSign.setUseOutKeystore(isUseOutKeystore);
jarSign.execute();
}
/**
* Returns a <tt>List</tt> of the {@link org.apache.maven.plugin.war.packaging.WarPackagingTask}
* instances to invoke to perform the packaging.
*
* @param overlayManager the overlay manager
* @return the list of packaging tasks
* @throws MojoExecutionException if the packaging tasks could not be built
*/
private List getPackagingTasks( OverlayManager overlayManager )
throws MojoExecutionException
{
final List packagingTasks = new ArrayList();
if ( useCache )
{
packagingTasks.add( new DependenciesAnalysisPackagingTask() );
}
final List resolvedOverlays = overlayManager.getOverlays();
final Iterator it = resolvedOverlays.iterator();
while ( it.hasNext() )
{
Overlay overlay = (Overlay) it.next();
if ( overlay.isCurrentProject() )
{
packagingTasks.add( new WarProjectPackagingTask( webResources, webXml, containerConfigXML ) );
}
else
{
packagingTasks.add( new OverlayPackagingTask( overlay ) );
}
}
return packagingTasks;
}
/**
* Returns a <tt>List</tt> of the {@link org.apache.maven.plugin.war.packaging.WarPostPackagingTask}
* instances to invoke to perform the post-packaging.
*
* @return the list of post packaging tasks
*/
private List getPostPackagingTasks()
{
final List postPackagingTasks = new ArrayList();
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 String defaultWarfilterLibs;
private String defaultWarlibRelativeDirectory;
private final ArtifactFactory artifactFactory;
private final WebappStructure webappStructure;
private final File webappDirectory;
private final OverlayManager overlayManager;
private final List filterWrappers;
private List nonFilteredFileExtensions;
private boolean filteringDeploymentDescriptors;
public DefaultWarPackagingContext( File webappDirectory, final WebappStructure webappStructure,
final OverlayManager overlayManager, List filterWrappers,
List nonFilteredFileExtensions, boolean filteringDeploymentDescriptors,
ArtifactFactory artifactFactory )
{
this.webappDirectory = webappDirectory;
this.webappStructure = webappStructure;
this.overlayManager = overlayManager;
this.filterWrappers = filterWrappers;
this.artifactFactory = artifactFactory;
this.filteringDeploymentDescriptors = filteringDeploymentDescriptors;
this.nonFilteredFileExtensions = nonFilteredFileExtensions == null ? Collections.EMPTY_LIST
: nonFilteredFileExtensions;
this.defaultWarlibRelativeDirectory = libRelativeWebappDirectory;
this.defaultWarfilterLibs = filterLibs;
// 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
final Iterator it = overlayManager.getOverlayIds().iterator();
while ( it.hasNext() )
{
String overlayId = (String) it.next();
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 getFilters()
{
return filters;
}
public WebappStructure getWebappStructure()
{
return webappStructure;
}
public List getOwnerIds()
{
return overlayManager.getOverlayIds();
}
public MavenFileFilter getMavenFileFilter()
{
return mavenFileFilter;
}
public List 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 String getFilterLibs() {
return this.defaultWarfilterLibs;
}
public String getLibRelativeWebappDirectory() {
return this.defaultWarlibRelativeDirectory;
}
}
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 getOverlays()
{
return overlays;
}
public void setOverlays( List 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 getFilters()
{
return filters;
}
public void setFilters( List 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 getNonFilteredFileExtensions()
{
return nonFilteredFileExtensions;
}
public void setNonFilteredFileExtensions( List nonFilteredFileExtensions )
{
this.nonFilteredFileExtensions = nonFilteredFileExtensions;
}
public ArtifactFactory getArtifactFactory()
{
return this.artifactFactory;
}
public void setArtifactFactory( ArtifactFactory artifactFactory )
{
this.artifactFactory = artifactFactory;
}
}
5.修改 ArtifactsPackagingTask.java
package org.apache.maven.plugin.war.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 org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.war.Overlay;
import org.codehaus.plexus.interpolation.InterpolationException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
/**
* Handles the artifacts that needs to be packaged in the web application.
*
* @author Stephane Nicoll
*
* @version $Id: ArtifactsPackagingTask.java 682073 2008-08-02 22:32:18Z dennisl $
*/
public class ArtifactsPackagingTask
extends AbstractWarPackagingTask
{
public static final String TLD_PATH = "WEB-INF/tld/";
public static final String SERVICES_PATH = "WEB-INF/services/";
private final Set artifacts;
private final String id;
public ArtifactsPackagingTask( Set artifacts )
{
this.artifacts = artifacts;
this.id = Overlay.currentProjectInstance().getId();
}
/**
* add by
* @param filterName
* @return
*/
String[] libFilters ;
private boolean filterFile(String filterName )
{
boolean returnFlag = true;
if ( libFilters != null ){
for(int i=0;i<libFilters.length;i++)
{
String filterRule = libFilters[i];
if( filterName.lastIndexOf(filterRule) !=-1)
{
returnFlag = false;
break;
}
}
}
return returnFlag;
}
public void performPackaging( WarPackagingContext context )
throws MojoExecutionException
{
try
{
final ScopeArtifactFilter filter = new ScopeArtifactFilter( Artifact.SCOPE_RUNTIME );
final List duplicates = findDuplicates( context, artifacts );
for ( Iterator iter = artifacts.iterator(); iter.hasNext(); )
{
Artifact artifact = (Artifact) iter.next();
String targetFileName = getArtifactFinalName( context, artifact );
context.getLog().debug( "Processing: " + targetFileName );
if ( duplicates.contains( targetFileName ) )
{
context.getLog().debug( "Duplicate found: " + targetFileName );
targetFileName = artifact.getGroupId() + "-" + targetFileName;
context.getLog().debug( "Renamed to: " + targetFileName );
}
context.getWebappStructure().registerTargetFileName( artifact, targetFileName );
if ( !artifact.isOptional() && filter.include( artifact ) )
{
try
{
String type = artifact.getType();
if ( "tld".equals( type ) )
{
copyFile( id, context, artifact.getFile(), TLD_PATH + targetFileName );
}
else if ( "aar".equals( type ) )
{
copyFile( id, context, artifact.getFile(), SERVICES_PATH + targetFileName );
}
else if ( "jar".equals( type ) || "ejb".equals( type ) || "ejb-client".equals( type )
|| "test-jar".equals( type ) )
{
// copyFile( id, context, artifact.getFile(), LIB_PATH + targetFileName );
if ( context.getFilterLibs() !=null )
libFilters =context.getFilterLibs().split(",");
if(filterFile(targetFileName)){
if ( context.getLibRelativeWebappDirectory()!= null )
{
copyFile( id, context, artifact.getFile(), context.getLibRelativeWebappDirectory() + targetFileName );
}
else
copyFile( id, context, artifact.getFile(), LIB_PATH + targetFileName );
}
}
else if ( "par".equals( type ) )
{
targetFileName = targetFileName.substring( 0, targetFileName.lastIndexOf( '.' ) ) + ".jar";
copyFile( id, context, artifact.getFile(), LIB_PATH + targetFileName );
}
else if ( "war".equals( type ) )
{
// Nothing to do here, it is an overlay and it's already handled
context.getLog().debug( "war artifacts are handled as overlays, ignoring[" + artifact + "]" );
}
else if ( "zip".equals( type ) )
{
// Nothing to do here, it is an overlay and it's already handled
context.getLog().debug( "zip artifacts are handled as overlays, ignoring[" + artifact + "]" );
}
else
{
context.getLog().debug(
"Artifact of type[" + type + "] is not supported, ignoring[" + artifact + "]" );
}
}
catch ( IOException e )
{
throw new MojoExecutionException( "Failed to copy file for artifact[" + artifact + "]", e );
}
}
}
}
catch ( InterpolationException e )
{
throw new MojoExecutionException( e.getMessage(), e );
}
}
/**
* Searches a set of artifacts for duplicate filenames and returns a list
* of duplicates.
*
* @param context the packaging context
* @param artifacts set of artifacts
* @return List of duplicated artifacts as bundling file names
*/
private List findDuplicates( WarPackagingContext context, Set artifacts )
throws InterpolationException
{
List duplicates = new ArrayList();
List identifiers = new ArrayList();
for ( Iterator iter = artifacts.iterator(); iter.hasNext(); )
{
Artifact artifact = (Artifact) iter.next();
String candidate = getArtifactFinalName( context, artifact );
if ( identifiers.contains( candidate ) )
{
duplicates.add( candidate );
}
else
{
identifiers.add( candidate );
}
}
return duplicates;
}
}
6. 添加签名类JarSign.java
package org.apache.maven.plugin.war;
import java.io.File;
import java.io.FileFilter;
import org.apache.maven.plugin.jar.JarSignMojo;
import org.codehaus.mojo.keytool.GenkeyMojo;
import org.codehaus.mojo.webstart.SignConfig;
import org.codehaus.mojo.webstart.JnlpMojo.KeystoreConfig;
/**
* @goal jarSigner
* @phase package
*/
public class JarSign {
protected File workDirectory;
private String relativeLibPath;
private SignConfig sign;
private KeystoreConfig keystore;
private boolean verbose;
private boolean isUseOutKeystore;
public void execute() {
if (sign != null) {
if ( !isUseOutKeystore)
genKeyStore();
signJars();
}
}
/**
* return the number of signed jars
*/
private int signJars() {
File directory = new File(workDirectory, relativeLibPath);
FileFilter fileFilter = new FileFilter() {
public boolean accept(File pathname) {
String fileName = pathname.getName();
boolean returnFlag = true;
if (fileName.lastIndexOf(".jar") == 1)
returnFlag = false;
return returnFlag;
}
};
File[] jarFiles = directory.listFiles(fileFilter);
if (jarFiles == null || jarFiles.length == 0 ) {
return 0;
}
JarSignMojo signJar = new JarSignMojo();
signJar.setAlias(sign.getAlias());
File storeKeyBasedir = new File(workDirectory, relativeLibPath);
signJar.setBasedir(storeKeyBasedir);
signJar.setKeypass(sign.getKeypass());
signJar.setKeystore(sign.getKeystore());
signJar.setSigFile(sign.getSigfile());
signJar.setStorepass(sign.getStorepass());
// signJar.setType(sign.getStoretype());
// signJar.setVerbose(this.verbose);
signJar.setWorkingDir(getWorkDirectory());
// signJar.setVerify(sign.getVerify());
for (int i = 0; i < jarFiles.length; i++) {
signJar.setJarPath(jarFiles[i]);
// for some reason, it appears that the signed jar field is not null
// ?
signJar.setSignedJar(null);
// long lastModified = jarFiles[i].lastModified();
try{
signJar.execute();
}catch(Exception e)
{
System.out.println(e);
}
// jarFiles[i].setLastModified(lastModified);
}
return jarFiles.length;
}
private void genKeyStore() {
try {
File keystoreFile = new File(getWorkDirectory(), sign.getKeystore());
if (keystoreFile.exists()) {
keystoreFile.delete();
}
GenkeyMojo genKeystore = new GenkeyMojo();
genKeystore.setAlias(sign.getAlias());
genKeystore.setDname(sign.getDname());
// genKeystore.setKeyalg(sign.getKeyalg());
genKeystore.setKeypass(sign.getKeypass());
// genKeystore.setKeysize(sign.getKeysize());
genKeystore.setKeystore( sign.getKeystore());
// genKeystore.setSigalg(sign.getSigalg());
genKeystore.setStorepass(sign.getStorepass());
// genKeystore.setStoretype(sign.getStoretype());
// genKeystore.setValidity(sign.getValidity());
// genKeystore.setVerbose(this.verbose);
// System.out.println( "getKeystore:"+sign.getKeystore());
// System.out.println( "workDirectory:"+getWorkDirectory().getAbsolutePath());
genKeystore.setWorkingDir(getWorkDirectory());
genKeystore.execute();
} catch(Exception e){
System.out.println( e);
}
}
public File getWorkDirectory() {
return workDirectory;
}
public void setWorkDirectory(File workDirectory) {
this.workDirectory = workDirectory;
}
public String getRelativeLibPath() {
return relativeLibPath;
}
public void setRelativeLibPath(String relativeLibPath) {
this.relativeLibPath = relativeLibPath;
}
public SignConfig getSign() {
return sign;
}
public void setSign(SignConfig sign) {
this.sign = sign;
}
public KeystoreConfig getKeystore() {
return keystore;
}
public void setKeystore(KeystoreConfig keystore) {
this.keystore = keystore;
}
public boolean isVerbose() {
return verbose;
}
public void setVerbose(boolean verbose) {
this.verbose = verbose;
}
public boolean isUseOutKeystore() {
return isUseOutKeystore;
}
public void setUseOutKeystore(boolean isUseOutKeystore) {
this.isUseOutKeystore = isUseOutKeystore;
}
}
7. 修改你的Pom.xml
<artifactId>maven-war-plugin</artifactId>
<packaging>maven-plugin</packaging>
<name>Maven WAR Plugin</name>
<version>2.1-yours-3</version>
8. 安装mvn install
9. 在你的JNLP项目中引起该插件(在pom.xml添加以下)
<build>
<finalName>spcclient</finalName>
<directory>target</directory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.1-scion-3</version>
<configuration>
<libRelativeWebappDirectory>lib/</libRelativeWebappDirectory>
<filterLibs>jstl,standard,commons-dbcp,commons-pool,msbase,mssqlserver,msutil,postgresql</filterLibs>
<relativeLibPath>lib</relativeLibPath>
<isUseOutKeystore>false</isUseOutKeystore>
<verbose>false</verbose>
<sign>
<keystore>spc.keystore</keystore>
<alias>jshopfloor</alias>
<storepass>jshopfloorpass</storepass>
<keypass>jshopfloorpass</keypass>
<dnameCn>xxx</dnameCn>
<dnameOu>xxx</dnameOu>
<dnameO>Sanmina-SCI</dnameO>
<dnameL>ShenZhen</dnameL>
<dnameSt>GuangDong</dnameSt>
<dnameC>CN</dnameC>
<verify>false</verify>
<validity>1</validity>
</sign>
<keystore>
<delete>true</delete>
<gen>true</gen>
</keystore>
</configuration>
</plugin>
</plugins>
</build>