org.eclipse.cbi.maven.plugins.winsigner.SignMojo.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.cbi.maven.plugins.winsigner.SignMojo.java

Source

/*******************************************************************************
 * Copyright (c) 2013 Eclipse Foundation and others 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 * Caroline McQuatt, Mike Lim - initial implementation
 *******************************************************************************/

package org.eclipse.cbi.maven.plugins.winsigner;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.io.RawInputStreamFacade;

/**
 * Signs project main and attached artifact using 
 * <a>href="http://wiki.eclipse.org/IT_Infrastructure_Doc#Sign_my_plugins.2FZIP_files.3F">Eclipse winsigner webservice</a>.
 * 
 * @goal sign
 * @phase package
 * @requiresProject
 * @description runs the eclipse signing process
 */
public class SignMojo extends AbstractMojo {
    /**
      * Official eclipse signer service url as described in
      * http://wiki.eclipse.org/IT_Infrastructure_Doc#Sign_my_plugins.2FZIP_files.3F
      */
    //private String signerUrl = "http://build.eclipse.org:31338/sign";
    private String signerUrl = "http://s.mjlim.net:1069/mikel/signing/winsign.php"; // Just for testing! This does no actual signing, just returns the file verbatim and logs at http://s.mjlim.net:1069/mikel/signing/sign_log.txt

    /**
     * @parameter expression="${project.build.directory}"
     */
    private File workdir;

    /**
     * @parameter expression="${project.artifactId}"
     */
    private String artifactID;

    /**
     * List of full executable paths.
     * If configured only these executables will be signed.
     * @parameter expression="${signFiles}"
     */
    private String[] signFiles;

    /**
     * Base dir to search for executables to sign.
     * If NOT configured baseSearchDir is ${project.build.directory}/products/${project.artifactId/}
     * @parameter expression="${baseSearchDir}
     */
    private String baseSearchDir;

    /**
     * List of file names to sign.
     * If NOT configured 'eclipse.exe' and 'eclipsec.exe' are signed. 
     * @parameter expression="${fileNames}
     */
    private String[] fileNames;

    public void execute() throws MojoExecutionException, MojoFailureException {
        //exe paths are configured
        if (signFiles != null && !(signFiles.length == 0)) {
            for (String path : signFiles) {
                signArtifact(new File(path));
            }
        } else { //perform search
            if (fileNames == null || fileNames.length == 0) {
                fileNames = new String[2];
                fileNames[0] = "eclipse.exe";
                fileNames[1] = "eclipsec.exe";
            }
            File searchDir = getSearchDir();
            if (searchDir != null) {
                traverseDirectory(searchDir);
            }
        }

    }

    /**
     * @return Directory to start the search from or 
     *          null if the directory cannot be found. A file
     *          will not be returned.
     */
    private File getSearchDir() {
        //base search dir is set
        if (baseSearchDir != null && !baseSearchDir.isEmpty()) {
            File dir = new File(baseSearchDir);
            if (dir.isDirectory()) {
                return dir;
            } else {
                getLog().error(dir + " is not a valid directory, failed to sign artifacts.");
                return null;
            }
        } else { //deriving search path
            if (artifactID == null || artifactID.isEmpty()) {
                getLog().error("${project.artifactID} is not available, failed to sign artifacts.");
                return null;
            }
            StringBuffer path = new StringBuffer(workdir.getPath());
            path.append("/products/");
            path.append(artifactID);
            File dir = new File(path.toString());

            if (dir.isDirectory()) {
                return dir;
            } else {
                getLog().error(
                        "Derived directory: " + dir + " is not a valid directory, failed to sign artifacts.");
                return null;
            }
        }
    }

    /**
     * searches the base directory for files to sign
     * @param files
     * @throws MojoExecutionException
     */
    private void traverseDirectory(File dir) throws MojoExecutionException {
        if (dir.isDirectory()) {
            getLog().debug("searching " + dir.getAbsolutePath());
            for (File file : dir.listFiles()) {
                if (file.isFile()) {
                    String fileName = file.getName();
                    for (String allowedName : fileNames) {
                        if (fileName.equals(allowedName)) {
                            signArtifact(file); // signs the file
                        }
                    }
                } else if (file.isDirectory()) {
                    traverseDirectory(file);
                }
            }
        }
    }

    /**
     * signs the file
     * @param file
     * @throws MojoExecutionException
     */
    protected void signArtifact(File file) throws MojoExecutionException {
        try {
            if (!file.isFile() || !file.canRead()) {
                getLog().warn(file + " is either not a file or cannot be read, the artifact is not signed.");
                return; // Can't read this. Likely a directory.
            }

            final long start = System.currentTimeMillis();

            workdir.mkdirs();
            File tempSigned = File.createTempFile(file.getName(), ".signed-exe", workdir);
            try {
                postFile(file, tempSigned);
                if (!tempSigned.canRead() || tempSigned.length() <= 0) {
                    throw new MojoExecutionException("Could not sign artifact " + file);
                }
                FileUtils.copyFile(tempSigned, file);
            } finally {
                tempSigned.delete();
            }
            getLog().info("Signed " + file + " in " + ((System.currentTimeMillis() - start) / 1000) + " seconds.");
        } catch (IOException e) {
            throw new MojoExecutionException("Could not sign file " + file, e);
        }
    }

    /**
     * helper to send the file to the signing service
     * @param source file to send
     * @param target file to copy response to
     * @throws IOException
     * @throws MojoExecutionException
     */
    private void postFile(File source, File target) throws IOException, MojoExecutionException {
        HttpClient client = new DefaultHttpClient();
        HttpPost post = new HttpPost(signerUrl);

        MultipartEntity reqEntity = new MultipartEntity();
        reqEntity.addPart("file", new FileBody(source));
        post.setEntity(reqEntity);

        HttpResponse response = client.execute(post);
        int statusCode = response.getStatusLine().getStatusCode();

        HttpEntity resEntity = response.getEntity();
        if (statusCode >= 200 && statusCode <= 299 && resEntity != null) {
            InputStream is = resEntity.getContent();
            try {
                FileUtils.copyStreamToFile(new RawInputStreamFacade(is), target);
            } finally {
                IOUtil.close(is);
            }
        } else {
            throw new MojoExecutionException("Signer replied " + response.getStatusLine());
        }
    }
}