package org.codehaus.mojo.webstart;
/*
* 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.FileFilter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.lang.SystemUtils;
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.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.jar.JarSignVerifyMojo;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.archiver.manager.ArchiverManager;
import org.codehaus.plexus.util.DirectoryScanner;
import org.codehaus.plexus.util.FileUtils;
/**
* The superclass for all JNLP generating MOJOs.
*
* @author Kevin Stembridge
* @author $LastChangedBy$
* @since 28 May 2007
* @version $Revision$
*
*/
public abstract class AbstractBaseJnlpMojo extends AbstractMojo
{
private static final String DEFAULT_RESOURCES_DIR = "src/main/jnlp/resources";
/** unprocessed files (that will be signed) are prefixed with this */
private static final String UNPROCESSED_PREFIX = "unprocessed_";
/**
* Artifact resolver, needed to download source jars for inclusion in classpath.
*
* @component
* @required
* @readonly
*/
private ArtifactResolver artifactResolver;
/**
* Artifact factory, needed to download source jars for inclusion in classpath.
*
* @component
* @required
* @readonly
*/
private ArtifactFactory artifactFactory;
/**
* @parameter default-value="${localRepository}"
* @required
* @readonly
*/
private ArtifactRepository localRepository;
/**
* The collection of remote artifact repositories.
*
* @parameter default-value="${project.remoteArtifactRepositories}"
* @readonly
* @required
*/
private List remoteRepositories;
/**
* The directory in which files will be stored prior to processing.
*
* @parameter default-value="${project.build.directory}/jnlp"
* @required
*/
private File workDirectory;
/**
* The path where the libraries are placed within the jnlp structure.
*
* @parameter default-value=""
*/
protected String libPath;
/**
* The location of the directory (relative or absolute) containing non-jar resources that
* are to be included in the JNLP bundle.
*
* @parameter
*/
private File resourcesDirectory;
/**
* The location where the JNLP Velocity template files are stored.
*
* @parameter default-value="${project.basedir}/src/main/jnlp"
* @required
*/
private File templateDirectory;
/**
* Indicates whether or not jar resources should be compressed
* using pack200. Setting this value to true requires SDK 5.0 or greater.
*
* @parameter default-value="false"
*/
private boolean pack200;
/**
* The Sign Config
*
* @parameter implementation="org.codehaus.mojo.webstart.JarSignMojoConfig"
*/
private SignConfig sign;
/**
* Indicates whether or not jar files should be verified after signing.
*
* @parameter default-value="true"
*/
private boolean verifyjar;
/**
* Indicates whether or not gzip archives will be created for each of the jar
* files included in the webstart bundle.
*
* @parameter default-value="false"
*/
private boolean gzip;
/**
* Enable verbose output.
*
* @parameter expression="${verbose}" default-value="false"
*/
private boolean verbose;
/**
* Set to true to exclude all transitive dependencies.
*
* @parameter
*/
private boolean excludeTransitive;
private final List modifiedJnlpArtifacts = new ArrayList();
// the jars to sign and pack are selected if they are prefixed by UNPROCESSED_PREFIX.
// as the plugin copies the new versions locally before signing/packing them
// we just need to see if the plugin copied a new version
// We achieve that by only filtering files modified after the plugin was started
// Note: if other files (the pom, the keystore config) have changed, one needs to clean
private final FileFilter unprocessedJarFileFilter;
private final FileFilter processedJarFileFilter;
private final FileFilter unprocessedPack200FileFilter;
/**
* Define whether to remove existing signatures.
*
* @parameter alias="unsign" default-value="false"
*/
private boolean unsignAlreadySignedJars;
/**
* To look up Archiver/UnArchiver implementations
*
* @component
* @required
*/
protected ArchiverManager archiverManager;
/**
* Creates a new {@code AbstractBaseJnlpMojo}.
*/
public AbstractBaseJnlpMojo()
{
processedJarFileFilter = new FileFilter()
{
public boolean accept( File pathname )
{
return pathname.isFile() && pathname.getName().endsWith( ".jar" )
&& ! pathname.getName().startsWith( UNPROCESSED_PREFIX );
}
};
unprocessedJarFileFilter = new FileFilter()
{
public boolean accept( File pathname )
{
return pathname.isFile() && pathname.getName().startsWith( UNPROCESSED_PREFIX )
&& pathname.getName().endsWith( ".jar" );
}
};
unprocessedPack200FileFilter = new UnprocessedPack200FileFilter();
}
protected void makeWorkingDirIfNecessary() throws MojoExecutionException
{
if ( !getWorkDirectory().exists() && !getWorkDirectory().mkdirs() )
{
throw new MojoExecutionException( "Failed to create: " + getWorkDirectory().getAbsolutePath() );
}
// check and create the library path
if ( !getLibDirectory().exists() && !getLibDirectory().mkdirs() )
{
throw new MojoExecutionException( "Failed to create: " + getLibDirectory().getAbsolutePath() );
}
}
public abstract MavenProject getProject();
/**
* Returns the working directory. This is the directory in which files and resources
* will be placed in order to be processed prior to packaging.
* @return Returns the value of the workDirectory field.
*/
protected File getWorkDirectory()
{
return workDirectory;
}
/**
* Returns the library directory. If not libPath is configured, the working directory is returned.
* @return Returns the value of the libraryDirectory field.
*/
protected File getLibDirectory()
{
if ( getLibPath() != null )
{
return new File( getWorkDirectory(), getLibPath() );
}
return getWorkDirectory();
}
/**
* Returns the library path. This is ths subpath within the working directory, where the libraries are placed.
* If the path is not configured it is <code>null</code>.
* @return the library path or <code>null</code> if not configured.
*/
public String getLibPath()
{
if ( ( libPath == null ) || ( libPath.trim().length() == 0 ) )
{
return null;
}
return libPath;
}
/**
* Returns the location of the directory containing
* non-jar resources that are to be included in the JNLP bundle.
*
* @return Returns the value of the resourcesDirectory field, never null.
*/
protected File getResourcesDirectory()
{
if ( resourcesDirectory == null )
{
resourcesDirectory = new File( getProject().getBasedir(), DEFAULT_RESOURCES_DIR );
}
return resourcesDirectory;
}
/**
* Returns the file handle to the directory containing the Velocity templates for the JNLP
* files to be generated.
* @return Returns the value of the templateDirectory field.
*/
protected File getTemplateDirectory()
{
return templateDirectory;
}
/**
* Returns the ArtifactFactory that can be used to create artifacts that
* need to be retrieved from maven artifact repositories.
* @return Returns the value of the artifactFactory field.
*/
protected ArtifactFactory getArtifactFactory()
{
return artifactFactory;
}
/**
* Returns the ArtifactResolver that can be used to retrieve artifacts
* from maven artifact repositories.
* @return Returns the value of the artifactResolver field.
*/
protected ArtifactResolver getArtifactResolver()
{
return artifactResolver;
}
/**
* Returns the local artifact repository.
* @return Returns the value of the localRepository field.
*/
protected ArtifactRepository getLocalRepository()
{
return localRepository;
}
/**
* Returns the collection of remote artifact repositories for the current
* Maven project.
* @return Returns the value of the remoteRepositories field.
*/
protected List getRemoteRepositories()
{
return remoteRepositories;
}
/**
* Returns the flag that indicates whether or not jar resources
* will be compressed using pack200.
*
* @return Returns the value of the pack200 field.
*/
public boolean isPack200()
{
return pack200;
}
/**
* Returns jar signing configuration element.
* @return Returns the value of the sign field.
*/
protected SignConfig getSign()
{
return sign;
}
/**
* Returns the flag that indicates whether or not a gzip should be
* created for each jar resource.
* @return Returns the value of the gzip field.
*/
protected boolean isGzip()
{
return gzip;
}
/**
* Returns the flag that indicates whether or not to provide verbose output.
* @return Returns the value of the verbose field.
*/
protected boolean isVerbose()
{
return verbose;
}
/**
* Returns the flag that indicates whether or not jars should be verified after signing.
* @return Returns the value of the verifyjar field.
*/
protected boolean isVerifyjar()
{
return verifyjar;
}
/**
* Returns the flag that indicates whether or not all transitive dependencies will be excluded
* from the generated JNLP bundle.
* @return Returns the value of the excludeTransitive field.
*/
protected boolean isExcludeTransitive()
{
return this.excludeTransitive;
}
/**
* Returns the collection of artifacts that have been modified
* since the last time this mojo was run.
* @return Returns the value of the modifiedJnlpArtifacts field.
*/
protected List getModifiedJnlpArtifacts()
{
return modifiedJnlpArtifacts;
}
/**
* Confirms that if Pack200 is enabled, the MOJO is being executed in at least a Java 1.5 JVM.
*
* @throws MojoExecutionException
*/
protected void checkPack200() throws MojoExecutionException
{
final float javaVersion5 = 1.5f;
if ( isPack200() && ( SystemUtils.JAVA_VERSION_FLOAT < javaVersion5 ) )
{
throw new MojoExecutionException(
"Configuration error: Pack200 compression is only available on SDK 5.0 or above." );
}
}
protected void copyResources( File resourcesDir, File workDirectory ) throws IOException
{
if ( !resourcesDir.exists() && getLog().isInfoEnabled() )
{
getLog().info( "No resources found in " + resourcesDir.getAbsolutePath() );
}
else
{
if ( ! resourcesDir.isDirectory() )
{
getLog().debug( "Not a directory: " + resourcesDir.getAbsolutePath() );
}
else
{
getLog().debug( "Copying resources from " + resourcesDir.getAbsolutePath() );
// hopefully available from FileUtils 1.0.5-SNAPSHOT
//FileUtils.copyDirectoryStructure( resourcesDir , workDirectory );
// this may needs to be parametrized somehow
String excludes = concat( DirectoryScanner.DEFAULTEXCLUDES, ", " );
copyDirectoryStructure( resourcesDir, workDirectory, "**", excludes );
}
}
}
private static String concat( String[] array, String delim )
{
StringBuffer buffer = new StringBuffer();
for ( int i = 0; i < array.length; i++ )
{
if ( i > 0 )
{
buffer.append( delim );
}
String s = array[i];
buffer.append( s ).append( delim );
}
return buffer.toString();
}
private void copyDirectoryStructure( File sourceDirectory, File destinationDirectory, String includes,
String excludes )
throws IOException
{
if ( !sourceDirectory.exists() )
{
return;
}
List files = FileUtils.getFiles( sourceDirectory, includes, excludes );
for ( Iterator i = files.iterator(); i.hasNext(); )
{
File file = (File) i.next();
getLog().debug( "Copying " + file + " to " + destinationDirectory );
String path = file.getAbsolutePath().substring( sourceDirectory.getAbsolutePath().length() + 1 );
File destDir = new File( destinationDirectory, path );
getLog().debug( "Copying " + file + " to " + destDir );
if ( file.isDirectory() )
{
destDir.mkdirs();
}
else
{
FileUtils.copyFileToDirectory( file, destDir.getParentFile() );
}
}
}
/**
* Conditionally copy the file into the target directory.
* The operation is not performed when the target file exists and is up to date.
* The target file name is taken from the <code>sourceFile</code> name.
*
* @return <code>true</code> when the file was copied, <code>false</code> otherwise.
* @throws IllegalArgumentException if sourceFile is <code>null</code> or
* <code>sourceFile.getName()</code> is <code>null</code>
* @throws IOException if an error occurs attempting to copy the file.
*/
protected boolean copyFileToDirectoryIfNecessary( File sourceFile, File targetDirectory ) throws IOException
{
if ( sourceFile == null )
{
throw new IllegalArgumentException( "sourceFile is null" );
}
File targetFile = new File( targetDirectory, sourceFile.getName() );
boolean shouldCopy = ! targetFile.exists() || ( targetFile.lastModified() < sourceFile.lastModified() );
if ( shouldCopy )
{
FileUtils.copyFileToDirectory( sourceFile, targetDirectory );
}
else
{
getLog().debug( "Source file hasn't changed. Do not overwrite "
+ targetFile + " with " + sourceFile + "." );
}
return shouldCopy;
}
/**
* Conditionally copy the jar file into the target directory.
* The operation is not performed when a signed target file exists and is up to date.
* The signed target file name is taken from the <code>sourceFile</code> name.E
* The unsigned target file name is taken from the <code>sourceFile</code> name prefixed with UNPROCESSED_PREFIX.
* TODO this is confusing if the sourceFile is already signed. By unsigned we really mean 'unsignedbyus'
*
* @return <code>true</code> when the file was copied, <code>false</code> otherwise.
* @throws IllegalArgumentException if sourceFile is <code>null</code> or
* <code>sourceFile.getName()</code> is <code>null</code>
* @throws IOException if an error occurs attempting to copy the file.
*/
protected boolean copyJarAsUnprocessedToDirectoryIfNecessary( File sourceFile, File targetDirectory )
throws IOException
{
if ( sourceFile == null )
{
throw new IllegalArgumentException( "sourceFile is null" );
}
File signedTargetFile = new File( targetDirectory, sourceFile.getName() );
File unsignedTargetFile = new File( targetDirectory, UNPROCESSED_PREFIX + sourceFile.getName() );
boolean shouldCopy = !signedTargetFile.exists()
|| ( signedTargetFile.lastModified() < sourceFile.lastModified() );
shouldCopy = shouldCopy && ( !unsignedTargetFile.exists()
|| ( unsignedTargetFile.lastModified() < sourceFile.lastModified() ) );
if ( shouldCopy )
{
FileUtils.copyFile( sourceFile, unsignedTargetFile );
}
else
{
getLog().debug( "Source file hasn't changed. Do not reprocess "
+ signedTargetFile + " with " + sourceFile + "." );
}
return shouldCopy;
}
/**
* If sign is enabled, sign the jars, otherwise rename them into final jars
*/
protected void signOrRenameJars() throws MojoExecutionException, MojoFailureException
{
if ( getSign() != null )
{
getSign().init( getLog(), getWorkDirectory(), isVerbose() );
if ( unsignAlreadySignedJars() )
{
removeExistingSignatures( getLibDirectory(), unprocessedJarFileFilter );
}
if ( isPack200() )
{
// http://java.sun.com/j2se/1.5.0/docs/guide/deployment/deployment-guide/pack200.html
// we need to pack then unpack the files before signing them
Pack200.packJars( getLibDirectory(), unprocessedJarFileFilter, isGzip() );
Pack200.unpackJars( getLibDirectory(), unprocessedPack200FileFilter );
// As out current Pack200 ant tasks don't give us the ability to use a temporary area for
// creating those temporary packing, we have to delete the temporary files.
deleteFiles( getLibDirectory(), unprocessedPack200FileFilter );
// specs says that one should do it twice when there are unsigned jars??
// Pack200.unpackJars( applicationDirectory, updatedPack200FileFilter );
}
int signedJars = signJars( getLibDirectory(), unprocessedJarFileFilter );
if ( signedJars != getModifiedJnlpArtifacts().size() )
{
throw new IllegalStateException(
"The number of signed artifacts (" + signedJars + ") differ from the number of modified "
+ "artifacts (" + getModifiedJnlpArtifacts().size() + "). Implementation error" );
}
}
else
{
makeUnprocessedFilesFinal( getLibDirectory(), unprocessedJarFileFilter );
}
}
private int makeUnprocessedFilesFinal( File directory, FileFilter fileFilter ) throws MojoExecutionException
{
File[] jarFiles = directory.listFiles( fileFilter );
if ( getLog().isDebugEnabled() )
{
getLog().debug( "makeUnprocessedFilesFinal in " + directory + " found "
+ jarFiles.length + " file(s) to rename" );
}
if ( jarFiles.length == 0 )
{
return 0;
}
for ( int i = 0; i < jarFiles.length; i++ )
{
String unprocessedJarFileName = jarFiles[i].getName();
if ( !unprocessedJarFileName.startsWith( UNPROCESSED_PREFIX ) )
{
throw new IllegalStateException( "We are about to sign an non " + UNPROCESSED_PREFIX
+ " file with path: " + jarFiles[i].getAbsolutePath() );
}
File finalJar = new File( jarFiles[i].getParent(),
unprocessedJarFileName.substring( UNPROCESSED_PREFIX.length() ) );
if ( finalJar.exists() )
{
boolean deleted = finalJar.delete();
if ( !deleted )
{
throw new IllegalStateException( "Couldn't delete obsolete final jar: "
+ finalJar.getAbsolutePath() );
}
}
boolean renamed = jarFiles[i].renameTo( finalJar );
if ( !renamed )
{
throw new IllegalStateException( "Couldn't rename into final jar: " + finalJar.getAbsolutePath() );
}
}
return jarFiles.length;
}
/**
* @return the number of deleted files
*/
private int deleteFiles( File directory, FileFilter fileFilter ) throws MojoExecutionException
{
File[] files = directory.listFiles( fileFilter );
if ( getLog().isDebugEnabled() )
{
getLog().debug( "deleteFiles in " + directory + " found " + files.length + " file(s) to delete" );
}
if ( files.length == 0 )
{
return 0;
}
for ( int i = 0; i < files.length; i++ )
{
boolean deleted = files[i].delete();
if ( !deleted )
{
throw new IllegalStateException( "Couldn't delete file: " + files[i].getAbsolutePath() );
}
}
return files.length;
}
/**
* @return the number of signed jars
*/
private int signJars( File directory, FileFilter fileFilter ) throws MojoExecutionException, MojoFailureException
{
File[] jarFiles = directory.listFiles( fileFilter );
if ( getLog().isDebugEnabled() )
{
getLog().debug( "signJars in " + directory + " found " + jarFiles.length + " jar(s) to sign" );
}
if ( jarFiles.length == 0 )
{
return 0;
}
JarSignerMojo jarSigner = getSign().getJarSignerMojo();
for ( int i = 0; i < jarFiles.length; i++ )
{
String unprocessedJarFileName = jarFiles[i].getName();
if ( !unprocessedJarFileName.startsWith( UNPROCESSED_PREFIX ) )
{
throw new IllegalStateException( "We are about to sign an non " + UNPROCESSED_PREFIX
+ " file with path: " + jarFiles[i].getAbsolutePath() );
}
jarSigner.setJarPath( jarFiles[i] );
File signedJar = new File( jarFiles[i].getParent(),
unprocessedJarFileName.substring( UNPROCESSED_PREFIX.length() ) );
jarSigner.setSignedJar( signedJar );
if ( signedJar.exists() )
{
if ( !signedJar.delete() )
{
throw new IllegalStateException( "Couldn't delete obsolete signed jar: "
+ signedJar.getAbsolutePath() );
}
}
jarSigner.execute();
getLog().debug( "lastModified signedJar:" + signedJar.lastModified() + " unprocessed signed Jar:"
+ jarFiles[i].lastModified() );
// remove unprocessed files
// TODO wouldn't have to do that if we copied the unprocessed jar files in a temporary area
if ( !jarFiles[i].delete() )
{
throw new IllegalStateException( "Couldn't delete obsolete unprocessed jar: "
+ jarFiles[i].getAbsolutePath() );
}
}
return jarFiles.length;
}
protected URL findDefaultJnlpTemplateURL()
{
URL url = this.getClass().getClassLoader().getResource( "default-jnlp-template.vm" );
return url;
}
protected URL getWebstartJarURL()
{
String url = findDefaultJnlpTemplateURL().toString();
try
{
return new URL( url.substring( "jar:".length(), url.indexOf( "!" ) ) );
}
catch ( Exception e )
{
IllegalStateException iae = new IllegalStateException( "Failure to find webstart Jar URL: "
+ e.getMessage() );
iae.initCause( e );
throw iae;
}
}
/** @return something of the form jar:file:..../webstart-maven-plugin-.....jar!/ */
protected String getWebstartJarURLForVelocity()
{
String url = findDefaultJnlpTemplateURL().toString();
return url.substring( 0, url.indexOf( "!" ) + 2 );
}
/**
* Removes the signature of the files in the specified directory which satisfy the
* specified filter.
*
* @return the number of unsigned jars
*/
protected int removeExistingSignatures( File workDirectory, FileFilter updatedJarFileFilter )
throws MojoExecutionException
{
verboseLog( "Start removing existing signatures" );
// cleanup tempDir if exists
File tempDir = new File( workDirectory, "temp_extracted_jars" );
removeDirectory( tempDir );
// recreate temp dir
if ( !tempDir.mkdirs() )
{
throw new MojoExecutionException( "Error creating temporary directory: " + tempDir );
}
// process jars
File[] jarFiles = workDirectory.listFiles( updatedJarFileFilter );
for ( int i = 0; i < jarFiles.length; i++ )
{
if ( isJarSigned( jarFiles[i] ) )
{
verboseLog( "remove signature from : " + jarFiles[i] );
unsignJarFile( jarFiles[i], tempDir );
}
else
{
verboseLog( "not signed : " + jarFiles[i] );
}
}
// cleanup tempDir
removeDirectory( tempDir );
return jarFiles.length; // FIXME this is wrong. Not all jars are signed.
}
private boolean isJarSigned( File jarFile )
{
JarSignVerifyMojo verifyMojo = setupVerifyMojo();
verifyMojo.setJarPath( jarFile );
try
{
verifyMojo.execute();
return true;
}
catch ( MojoExecutionException e )
{
return false;
}
}
private void unsignJarFile( File jarFile, File tempDir ) throws MojoExecutionException
{
JarUnsignMojo unsignJar = new JarUnsignMojo();
unsignJar.setTempDir( tempDir );
unsignJar.setVerbose( isVerbose() );
unsignJar.setArchiverManager( archiverManager );
unsignJar.setJarPath( jarFile );
unsignJar.execute();
}
/**
* Returns a configured instance of the JarSignVerifyMojo to test whether a
* jar is already signed. The Mojo throws an exception to indicate that a
* jar is not signed yet.
*
* @return a configured instance of the JarSignVerifyMojo.
*/
private JarSignVerifyMojo setupVerifyMojo()
{
JarSignVerifyMojo verifyMojo = new JarSignVerifyMojo();
verifyMojo.setErrorWhenNotSigned( true );
verifyMojo.setWorkingDir( getWorkDirectory() );
return verifyMojo;
}
/**
* This is to try to workaround an issue with setting setLastModified.
* See MWEBSTART-28. May be removed later on if that doesn't help.
*/
/*
private boolean setLastModified( File file, long timestamp )
{
boolean result;
int nbretries = 3;
while ( ! (result = file.setLastModified( timestamp )) && ( nbretries-- > 0 ) )
{
getLog().warn("failure to change last modified timestamp... retrying ... "
+ "See MWEBSTART-28. (especially if you're on NFS).");
try
{
Thread.sleep( 4000 );
}
catch (InterruptedException ignore) {
//TODO should not be ignoring, because this class doesn't control the Thread policy
}
}
return result;
}
*/
protected void packJars()
{
if ( isPack200() )
{
getLog().debug( "packing jars" );
Pack200.packJars( getWorkDirectory(), processedJarFileFilter, isGzip() );
}
}
/**
* TODO finish comment
*
* @param artifact
* @param mainClass
* @return
* @throws MalformedURLException
*/
protected boolean artifactContainsClass( Artifact artifact, final String mainClass ) throws MalformedURLException
{
boolean containsClass = true;
// JarArchiver.grabFilesAndDirs()
ClassLoader cl = new java.net.URLClassLoader( new URL[]{ artifact.getFile().toURI().toURL() } );
Class c = null;
try
{
c = Class.forName( mainClass, false, cl );
}
catch ( ClassNotFoundException e )
{
getLog().debug( "artifact " + artifact + " doesn't contain the main class: " + mainClass );
containsClass = false;
}
catch ( Throwable t )
{
getLog().info( "artifact " + artifact + " seems to contain the main class: " + mainClass
+ " but the jar doesn't seem to contain all dependencies " + t.getMessage() );
}
if ( c != null )
{
getLog().debug( "Checking if the loaded class contains a main method." );
try
{
c.getMethod( "main", new Class[]{String[].class} );
}
catch ( NoSuchMethodException e )
{
getLog().warn( "The specified main class (" + mainClass
+ ") doesn't seem to contain a main method... "
+ "Please check your configuration." + e.getMessage() );
}
catch ( NoClassDefFoundError e )
{
// undocumented in SDK 5.0. is this due to the ClassLoader lazy loading the Method
// thus making this a case tackled by the JVM Spec (Ref 5.3.5)!
// Reported as Incident 633981 to Sun just in case ...
getLog().warn( "Something failed while checking if the main class contains the main() method. "
+ "This is probably due to the limited classpath we have provided to the class loader. "
+ "The specified main class (" + mainClass
+ ") found in the jar is *assumed* to contain a main method... " + e.getMessage() );
}
catch ( Throwable t )
{
getLog().error( "Unknown error: Couldn't check if the main class has a main method. "
+ "The specified main class (" + mainClass
+ ") found in the jar is *assumed* to contain a main method...", t );
}
}
return containsClass;
}
/**
* anonymous to inner to work-around qdox 1.6.1 bug (MPLUGIN-26)
*/
private static class UnprocessedPack200FileFilter implements FileFilter
{
public boolean accept( File pathname )
{
return pathname.isFile() && pathname.getName().startsWith( UNPROCESSED_PREFIX )
&& ( pathname.getName().endsWith( ".jar.pack.gz" ) || pathname.getName().endsWith( ".jar.pack" ) );
}
};
/**
*
* @return true if already signed jars should be unsigned prior to signing
* with own key.
*/
protected boolean unsignAlreadySignedJars()
{
return unsignAlreadySignedJars;
}
/**
* Delete the specified directory.
*
* @param dir
* the directory to delete
* @throws MojoExecutionException
*/
private void removeDirectory( File dir ) throws MojoExecutionException
{
if ( dir != null )
{
if ( dir.exists() && dir.isDirectory() )
{
getLog().info( "Deleting directory " + dir.getAbsolutePath() );
Utils.removeDir( dir );
}
}
}
/**
* Log as info when verbose or info is enabled, as debug otherwise.
*/
protected void verboseLog( String msg )
{
infoOrDebug( isVerbose() || getLog().isInfoEnabled(), msg );
}
/** if info is true, log as info(), otherwise as debug() */
private void infoOrDebug( boolean info , String msg )
{
if ( info )
{
getLog().info( msg );
}
else
{
getLog().debug( msg );
}
}
}