net.sf.jsignpdf.Signer.java Source code

Java tutorial

Introduction

Here is the source code for net.sf.jsignpdf.Signer.java

Source

/*
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (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.mozilla.org/MPL/
 * 
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 * 
 * The Original Code is 'JSignPdf, a free application for PDF signing'.
 * 
 * The Initial Developer of the Original Code is Josef Cacek.
 * Portions created by Josef Cacek are Copyright (C) Josef Cacek. All Rights Reserved.
 * 
 * Contributor(s): Josef Cacek.
 * 
 * Alternatively, the contents of this file may be used under the terms
 * of the GNU Lesser General Public License, version 2.1 (the  "LGPL License"), in which case the
 * provisions of LGPL License are applicable instead of those
 * above. If you wish to allow use of your version of this file only
 * under the terms of the LGPL License and not to allow others to use
 * your version of this file under the MPL, indicate your decision by
 * deleting the provisions above and replace them with the notice and
 * other provisions required by the LGPL License. If you do not delete
 * the provisions above, a recipient may use your version of this file
 * under either the MPL or the LGPL License.
 */
package net.sf.jsignpdf;

import static net.sf.jsignpdf.Constants.EXIT_CODE_NO_COMMAND;
import static net.sf.jsignpdf.Constants.EXIT_CODE_PARSE_ERR;
import static net.sf.jsignpdf.Constants.NEW_LINE;
import static net.sf.jsignpdf.Constants.RES;
import static net.sf.jsignpdf.Constants.VERSION;

import java.io.File;
import java.io.FileFilter;
import java.security.Provider;
import java.security.Security;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import javax.swing.UIManager;
import javax.swing.WindowConstants;

import net.sf.jsignpdf.ssl.SSLInitializer;
import net.sf.jsignpdf.utils.ConfigProvider;
import net.sf.jsignpdf.utils.GuiUtils;
import net.sf.jsignpdf.utils.KeyStoreUtils;
import net.sf.jsignpdf.utils.PKCS11Utils;

import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.ParseException;
import org.apache.commons.io.filefilter.AndFileFilter;
import org.apache.commons.io.filefilter.FileFileFilter;
import org.apache.commons.io.filefilter.WildcardFileFilter;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

/**
 * JSignPdf main class - it either process command line or if no argument is
 * given, sets system Look&Feel and creates SignPdfForm GUI.
 * 
 * @author Josef Cacek
 */
public class Signer {

    private final static Logger LOGGER = Logger.getLogger(Signer.class);
    static String pkcs11ProviderName = null;

    /**
     * Prints formatted help message (command line arguments).
     */
    private static void printHelp() {
        final HelpFormatter formatter = new HelpFormatter();
        formatter.printHelp(80, "java -jar JSignPdf.jar [file1.pdf [file2.pdf ...]]", RES.get("hlp.header"),
                SignerOptionsFromCmdLine.OPTS, NEW_LINE + RES.get("hlp.footer.exitCodes") + NEW_LINE
                        + StringUtils.repeat("-", 80) + NEW_LINE + RES.get("hlp.footer.examples"),
                true);
    }

    /**
     * Main.
     * 
     * @param args
     */
    public static void main(String[] args) {
        SignerOptionsFromCmdLine tmpOpts = null;

        if (args != null && args.length > 0) {
            tmpOpts = new SignerOptionsFromCmdLine();
            parseCommandLine(args, tmpOpts);
        }

        try {
            SSLInitializer.init();
        } catch (Exception e) {
            LOGGER.warn("Unable to re-configure SSL layer", e);
        }

        pkcs11ProviderName = PKCS11Utils
                .registerProvider(ConfigProvider.getInstance().getProperty("pkcs11config.path"));

        traceInfo();

        if (tmpOpts != null) {
            if (tmpOpts.isPrintVersion()) {
                System.out.println("JSignPdf version " + VERSION);
            }
            if (tmpOpts.isPrintHelp()) {
                printHelp();
            }
            if (tmpOpts.isListKeyStores()) {
                LOGGER.info(RES.get("console.keystores"));
                for (String tmpKsType : KeyStoreUtils.getKeyStores()) {
                    System.out.println(tmpKsType);
                }
            }
            if (tmpOpts.isListKeys()) {
                final String[] tmpKeyAliases = KeyStoreUtils.getKeyAliases(tmpOpts);
                LOGGER.info(RES.get("console.keys"));
                // list certificate aliases in the keystore
                for (String tmpCert : tmpKeyAliases) {
                    System.out.println(tmpCert);
                }
            }
            if (ArrayUtils.isNotEmpty(tmpOpts.getFiles())
                    || (!StringUtils.isEmpty(tmpOpts.getInFile()) && !StringUtils.isEmpty(tmpOpts.getOutFile()))) {
                signFiles(tmpOpts);
            } else {
                final boolean tmpCommand = tmpOpts.isPrintVersion() || tmpOpts.isPrintHelp()
                        || tmpOpts.isListKeyStores() || tmpOpts.isListKeys();
                if (!tmpCommand) {
                    // no valid command provided - print help and exit
                    printHelp();
                    exit(EXIT_CODE_NO_COMMAND);
                }
            }
            exit(0);
        } else {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (Exception e) {
                System.err.println("Can't set Look&Feel.");
            }
            SignPdfForm tmpForm = new SignPdfForm(WindowConstants.EXIT_ON_CLOSE);
            tmpForm.pack();
            GuiUtils.center(tmpForm);
            tmpForm.setVisible(true);
        }
    }

    /**
     * Writes info about security providers to the {@link Logger} instance. The
     * log-level for messages is TRACE.
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    private static void traceInfo() {
        if (LOGGER.isTraceEnabled()) {
            try {
                Provider[] aProvider = Security.getProviders();
                for (int i = 0; i < aProvider.length; i++) {
                    Provider provider = aProvider[i];
                    LOGGER.trace(
                            "Provider " + (i + 1) + " : " + provider.getName() + " " + provider.getInfo() + " :");
                    List keyList = new ArrayList(provider.keySet());
                    try {
                        Collections.sort(keyList);
                    } catch (Exception e) {
                        LOGGER.trace("Provider's properties keys can't be sorted", e);
                    }
                    Iterator keyIterator = keyList.iterator();
                    while (keyIterator.hasNext()) {
                        String key = (String) keyIterator.next();
                        LOGGER.trace(key + ": " + provider.getProperty(key));
                    }
                    LOGGER.trace("------------------------------------------------");
                }
            } catch (Exception e) {
                LOGGER.trace("Listing security providers failed", e);
            }
        }
    }

    /**
     * Sign the files
     * 
     * @param anOpts
     */
    private static void signFiles(SignerOptionsFromCmdLine anOpts) {
        final SignerLogic tmpLogic = new SignerLogic(anOpts);
        if (ArrayUtils.isEmpty(anOpts.getFiles())) {
            // we've used -lp (loadproperties) parameter
            if (!tmpLogic.signFile()) {
                exit(Constants.EXIT_CODE_ALL_SIG_FAILED);
            }
            return;
        }
        int successCount = 0;
        int failedCount = 0;

        for (final String wildcardPath : anOpts.getFiles()) {
            final File wildcardFile = new File(wildcardPath);

            File[] inputFiles;
            if (StringUtils.containsAny(wildcardFile.getName(), '*', '?')) {
                final File inputFolder = wildcardFile.getAbsoluteFile().getParentFile();
                final FileFilter fileFilter = new AndFileFilter(FileFileFilter.FILE,
                        new WildcardFileFilter(wildcardFile.getName()));
                inputFiles = inputFolder.listFiles(fileFilter);
                if (inputFiles == null) {
                    continue;
                }
            } else {
                inputFiles = new File[] { wildcardFile };
            }
            for (File inputFile : inputFiles) {
                final String tmpInFile = inputFile.getPath();
                if (!inputFile.canRead()) {
                    failedCount++;
                    System.err.println(RES.get("file.notReadable", new String[] { tmpInFile }));
                    continue;
                }
                anOpts.setInFile(tmpInFile);
                String tmpNameBase = inputFile.getName();
                String tmpSuffix = ".pdf";
                if (StringUtils.endsWithIgnoreCase(tmpNameBase, tmpSuffix)) {
                    tmpSuffix = StringUtils.right(tmpNameBase, 4);
                    tmpNameBase = StringUtils.left(tmpNameBase, tmpNameBase.length() - 4);
                }
                final StringBuilder tmpName = new StringBuilder(anOpts.getOutPath());
                tmpName.append(anOpts.getOutPrefix());
                tmpName.append(tmpNameBase).append(anOpts.getOutSuffix()).append(tmpSuffix);
                String outFile = anOpts.getOutFile();
                if (outFile == null)
                    anOpts.setOutFile(tmpName.toString());
                if (tmpLogic.signFile()) {
                    successCount++;
                } else {
                    failedCount++;
                }

            }
        }
        if (failedCount > 0) {
            exit(successCount > 0 ? Constants.EXIT_CODE_SOME_SIG_FAILED : Constants.EXIT_CODE_ALL_SIG_FAILED);
        }
    }

    /**
     * Parses the command line. Exits with error exit code when parsing fails.
     * 
     * @param args
     * @param opts
     */
    private static void parseCommandLine(String[] args, final SignerOptionsFromCmdLine opts) {
        try {
            opts.loadCmdLine(args);
        } catch (ParseException exp) {
            System.err.println("Unable to parse command line (Use -h for the help)\n" + exp.getMessage());
            exit(EXIT_CODE_PARSE_ERR);
        }
    }

    private static void exit(int exitCode) {
        PKCS11Utils.unregisterProvider(pkcs11ProviderName);
        System.exit(exitCode);
    }
}