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

org.apache.maven.plugin.jar.JarSignMojo Maven / Gradle / Ivy

package org.apache.maven.plugin.jar;

/*
 * 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.commons.lang.SystemUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectHelper;
import org.apache.maven.artifact.handler.ArtifactHandler;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.cli.CommandLineException;
import org.codehaus.plexus.util.cli.CommandLineUtils;
import org.codehaus.plexus.util.cli.Commandline;
import org.codehaus.plexus.util.cli.StreamConsumer;

import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;

/**
 * Signs a JAR using jarsigner.
 *
 * @author Jerome Lacoste
 * @version $Id: JarSignMojo.java 802529 2009-08-09 12:05:35Z bentmann $
 * @goal sign
 * @phase package
 * @requiresProject
 * @todo refactor the common code with javadoc plugin
 * @requiresDependencyResolution runtime
 * @deprecated As of version 2.3, this goal is no longer supported in favor of the dedicated maven-jarsigner-plugin.
 */
public class JarSignMojo
    extends AbstractMojo
{
    /**
     * Set this to true to disable signing.
     * Useful to speed up build process in development environment.
     *
     * @parameter expression="${maven.jar.sign.skip}" default-value="false"
     */
    private boolean skip;

    /**
     * The working directory in which the jarsigner executable will be run.
     *
     * @parameter expression="${workingdir}" default-value="${basedir}"
     * @required
     */
    private File workingDirectory;

    /**
     * Directory containing the generated JAR.
     *
     * @parameter expression="${project.build.directory}"
     * @required
     * @readonly
     */
    private File basedir;

    /**
     * Name of the generated JAR (without classifier and extension).
     *
     * @parameter alias="jarname" expression="${project.build.finalName}"
     * @required
     */
    private String finalName;

    /**
     * Path of the jar to sign. When specified, the finalName is ignored.
     *
     * @parameter alias="jarpath" default-value="${project.build.directory}/${project.build.finalName}.${project.packaging}"
     */
    private File jarPath;

    /**
     * See options.
     *
     * @parameter expression="${keystore}"
     */
    private String keystore;

    /**
     * See options.
     *
     * @parameter expression="${storepass}"
     */
    private String storepass;

    /**
     * See options.
     *
     * @parameter expression="${keypass}"
     */
    private String keypass;

    /**
     * See options.
     *
     * @parameter expression="${sigfile}"
     * @todo make a File?
     */
    private String sigfile;

    /**
     * See options.
     * 

* Not specifying this argument will sign the jar in-place (your original jar is going to be overwritten). * * @parameter expression="${signedjar}" */ private File signedjar; /** * See options. * The corresponding option in the command line is -storetype. * * @parameter expression="${type}" */ private String type; /** * See options. * * @parameter expression="${alias}" * @required */ private String alias; /** * Automatically verify a jar after signing it. *

* See options. * * @parameter expression="${verify}" default-value="false" */ private boolean verify; /** * Skip attaching the signed artifact. By default the signed artifact is attached. * This is not a Mojo parameter as we shouldn't need this when using this mojo. * Just needed when reusing the implementation. See MJAR-84 for discussions. */ private boolean skipAttachSignedArtifact; /** * Enable verbose. * See options. * * @parameter expression="${verbose}" default-value="false" */ private boolean verbose; /** * @component */ private MavenProjectHelper projectHelper; /** * The Maven project. * * @parameter expression="${project}" * @required * @readonly */ private MavenProject project; /** * Classifier to use for the generated artifact. * If not specified, the generated artifact becomes the primary artifact. * * @parameter expression="${classifier}" */ private String classifier; public void execute() throws MojoExecutionException { if ( skip ) { getLog().info( "Skipping JAR signing for file: " + getJarFile().getAbsolutePath() ); return; } if ( project != null ) { ArtifactHandler artifactHandler = project.getArtifact().getArtifactHandler(); if ( artifactHandler != null && !"java".equals( artifactHandler.getLanguage() ) ) { getLog().debug( "Not executing jar:sign as the project is not a Java module" ); return; } } // we use this mojo to check if there's a need to sign. // If we sign and if we need to verify, we reuse it to check the signature JarSignVerifyMojo verifyMojo = createJarSignVerifyMojo(); verifyMojo.setWorkingDir( workingDirectory ); verifyMojo.setBasedir( basedir ); File signedJarFile = signedjar != null ? signedjar : getJarFile(); verifyMojo.setVerbose( verbose ); verifyMojo.setJarPath( signedJarFile ); if ( signedJarFile.exists() ) { verifyMojo.setErrorWhenNotSigned( false ); verifyMojo.execute(); } if ( verifyMojo.isSigned() ) { getLog().info( "JAR " + signedJarFile.getAbsoluteFile() + " is already signed. Skipping." ); return; } signJar(); if ( this.verify ) { verifyMojo.setErrorWhenNotSigned( true ); verifyMojo.execute(); } } protected JarSignVerifyMojo createJarSignVerifyMojo() { return new JarSignVerifyMojo(); } File getJarFile() { if ( jarPath != null ) { return jarPath; } else { return AbstractJarMojo.getJarFile( basedir, finalName, null ); } } void signJar() throws MojoExecutionException { List arguments = new ArrayList(); Commandline commandLine = new Commandline(); commandLine.setExecutable( getJarsignerPath() ); addArgIf( arguments, verbose, "-verbose" ); // I believe Commandline to add quotes where appropriate, although I haven't tested it enough. // FIXME addArgIfNotEmpty will break those parameters containing a space. // Look at webapp:gen-keystore for a way to fix that addArgIfNotEmpty( arguments, "-keystore", this.keystore ); addArgIfNotEmpty( arguments, "-storepass", this.storepass ); addArgIfNotEmpty( arguments, "-keypass", this.keypass ); addArgIfNotEmpty( arguments, "-signedjar", this.signedjar ); addArgIfNotEmpty( arguments, "-storetype", this.type ); addArgIfNotEmpty( arguments, "-sigfile", this.sigfile ); arguments.add( getJarFile() ); addArgIf( arguments, alias != null, this.alias ); for ( Iterator it = arguments.iterator(); it.hasNext(); ) { commandLine.createArgument().setValue( it.next().toString() ); } commandLine.setWorkingDirectory( workingDirectory.getAbsolutePath() ); createParentDirIfNecessary( signedjar ); if ( signedjar == null ) { getLog().debug( "Signing JAR in-place (overwritting original JAR)." ); } if ( getLog().isDebugEnabled() ) { getLog().debug( "Executing: " + purgePassword( commandLine ) ); } // jarsigner may ask for some input if the parameters are missing or incorrect. // This should take care of it and make it fail gracefully final InputStream inputStream = new InputStream() { public int read() { return -1; } }; StreamConsumer outConsumer = new StreamConsumer() { public void consumeLine( String line ) { getLog().info( line ); } }; final StringBuffer errBuffer = new StringBuffer(); StreamConsumer errConsumer = new StreamConsumer() { public void consumeLine( String line ) { errBuffer.append( line ); getLog().warn( line ); } }; try { int result = executeCommandLine( commandLine, inputStream, outConsumer, errConsumer ); if ( result != 0 ) { throw new MojoExecutionException( "Result of " + purgePassword( commandLine ) + " execution is: \'" + result + "\'." ); } } catch ( CommandLineException e ) { throw new MojoExecutionException( "command execution failed", e ); } // signed in place, no need to attach if ( signedjar == null || skipAttachSignedArtifact ) { return; } if ( classifier != null ) { projectHelper.attachArtifact( project, "jar", classifier, signedjar ); } else { project.getArtifact().setFile( signedjar ); } } private String purgePassword( Commandline commandLine ) { String out = commandLine.toString(); if ( keypass != null && out.indexOf( keypass ) != -1 ) { out = StringUtils.replace( out, keypass, "******" ); } return out; } private void createParentDirIfNecessary( File file ) { if ( file != null ) { File fileDir = file.getParentFile(); if ( fileDir != null ) { // not a relative path boolean mkdirs = fileDir.mkdirs(); getLog().debug( "mdkirs: " + mkdirs + " " + fileDir ); } } } // taken from JavadocReport then slightly refactored // should probably share with other plugins that use $JAVA_HOME/bin tools /** * Get the path of jarsigner tool depending the OS. * * @return the path of the jarsigner tool */ private String getJarsignerPath() { return getJDKCommandPath( "jarsigner", getLog() ); } private static String getJDKCommandPath( String command, Log logger ) { String path = getJDKCommandExe( command ).getAbsolutePath(); logger.debug( command + " executable=[" + path + "]" ); return path; } private static File getJDKCommandExe( String command ) { String fullCommand = command + ( SystemUtils.IS_OS_WINDOWS ? ".exe" : "" ); File exe; // For IBM's JDK 1.2 if ( SystemUtils.IS_OS_AIX ) { exe = new File( SystemUtils.getJavaHome() + "/../sh", fullCommand ); } else if ( SystemUtils.IS_OS_MAC_OSX ) { exe = new File( SystemUtils.getJavaHome() + "/bin", fullCommand ); } else { exe = new File( SystemUtils.getJavaHome() + "/../bin", fullCommand ); } return exe; } // Helper methods. Could/should be shared e.g. with JavadocReport /** * Convenience method to add an argument to the command line * conditionally based on the given flag. * * @param arguments * @param b the flag which controls if the argument is added or not. * @param value the argument value to be added. */ private void addArgIf( List arguments, boolean b, String value ) { if ( b ) { arguments.add( value ); } } /** * Convenience method to add an argument to the command line * if the the value is not null or empty. *

* Moreover, the value could be comma separated. * * @param arguments * @param key the argument name. * @param value the argument value to be added. * @see #addArgIfNotEmpty(java.util.List,String,Object,boolean) */ private void addArgIfNotEmpty( List arguments, String key, Object value ) { addArgIfNotEmpty( arguments, key, value, false ); } /** * Convenience method to add an argument to the command line * if the the value is not null or empty. *

* Moreover, the value could be comma separated. * * @param arguments * @param key the argument name. * @param value the argument value to be added. * @param repeatKey repeat or not the key in the command line */ private void addArgIfNotEmpty( List arguments, String key, Object value, boolean repeatKey ) { if ( value != null && !StringUtils.isEmpty( value.toString() ) ) { arguments.add( key ); StringTokenizer token = new StringTokenizer( value.toString(), "," ); while ( token.hasMoreTokens() ) { String current = token.nextToken().trim(); if ( !StringUtils.isEmpty( current ) ) { arguments.add( current ); if ( token.hasMoreTokens() && repeatKey ) { arguments.add( key ); } } } } } // // methods used for tests purposes - allow mocking and simulate automatic setters // protected int executeCommandLine( Commandline commandLine, InputStream inputStream, StreamConsumer stream1, StreamConsumer stream2 ) throws CommandLineException { return CommandLineUtils.executeCommandLine( commandLine, inputStream, stream1, stream2 ); } public void setWorkingDir( File workingDir ) { this.workingDirectory = workingDir; } public void setBasedir( File basedir ) { this.basedir = basedir; } public void setKeystore( String keystore ) { this.keystore = keystore; } public void setKeypass( String keypass ) { this.keypass = keypass; } public void setSignedJar( File signedjar ) { this.signedjar = signedjar; } public void setAlias( String alias ) { this.alias = alias; } // hiding for now - I don't think this is required to be seen /* public void setFinalName( String finalName ) { this.finalName = finalName; } */ public void setJarPath( File jarPath ) { this.jarPath = jarPath; } public void setStorepass( String storepass ) { this.storepass = storepass; } public void setSigFile( String sigfile ) { this.sigfile = sigfile; } public void setType( String type ) { this.type = type; } public void setVerbose( boolean verbose ) { this.verbose = verbose; } public void setSkipAttachSignedArtifact( boolean skipAttachSignedArtifact ) { this.skipAttachSignedArtifact = skipAttachSignedArtifact; } public void setProject( MavenProject project ) { this.project = project; } public void setVerify( boolean verify ) { this.verify = verify; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy