iDynoOptimizer.MOEAFramework26.src.org.moeaframework.util.io.FileProtection.java Source code

Java tutorial

Introduction

Here is the source code for iDynoOptimizer.MOEAFramework26.src.org.moeaframework.util.io.FileProtection.java

Source

/* Copyright 2009-2015 David Hadka
 *
 * This file is part of the MOEA Framework.
 *
 * The MOEA Framework is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or (at your
 * option) any later version.
 *
 * The MOEA Framework is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with the MOEA Framework.  If not, see <http://www.gnu.org/licenses/>.
 */
package iDynoOptimizer.MOEAFramework26.src.org.moeaframework.util.io;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.Reader;
import java.io.Writer;
import java.security.DigestInputStream;
import java.security.DigestOutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.MessageFormat;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import iDynoOptimizer.MOEAFramework26.src.org.moeaframework.core.FrameworkException;
import iDynoOptimizer.MOEAFramework26.src.org.moeaframework.core.Settings;
import iDynoOptimizer.MOEAFramework26.src.org.moeaframework.util.CommandLineUtility;

/**
 * Detects corrupted files using the MD5 message digest in a format compatible
 * with the Unix command line utility {@code md5sum}.
 * 
 * <ol>
 *   <li>Strict mode - All files must be validated, otherwise exceptions are 
 *       thrown
 *   <li>Safe mode - Files with associated digest files are validated, but only
 *       warnings are printed if no digest file exists
 * </ol>
 */
public class FileProtection extends CommandLineUtility {

    /**
     * The property value for strict mode.
     */
    public static final String STRICT_MODE = "STRICT";

    /**
     * The property value for safe mode.
     */
    public static final String SAFE_MODE = "SAFE";

    /**
     * Private constructor to prevent instantiation.
     */
    private FileProtection() {
        super();
    }

    /**
     * Creates and returns a new instance of {@link MessageDigest}.
     * 
     * @return a new instance of {@code MessageDigest}
     * @throws FrameworkException if the message digest could not be created
     */
    private static MessageDigest createMessageDigest() {
        try {
            return MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            throw new FrameworkException(e);
        }
    }

    /**
     * Returns the digest file for the specified file.
     * 
     * @param file the file to be validated
     * @return the digest file for the specified file
     */
    public static File getDigestFile(File file) {
        return new File(file.getParentFile(),
                MessageFormat.format(Settings.getFileProtectionFormat(), file.getName()));
    }

    /**
     * Saves the message digest file in a format compatible with {@code md5sum}.
     * 
     * @param file the file to be validated
     * @param digest the message digest
     * @throws IOException if an I/O error occurred
     */
    private static void saveDigest(File file, byte[] digest) throws IOException {
        PrintStream ps = null;

        try {
            ps = new PrintStream(getDigestFile(file));

            ps.print(Hex.encodeHex(digest));
            ps.print("  ");
            ps.print(file.getPath());
        } finally {
            if (ps != null) {
                ps.close();
            }
        }
    }

    /**
     * Returns the digest value stored in the message digest file.
     * 
     * @param file the file to be validated
     * @return the message digest
     * @throws IOException if an I/O error occurred
     */
    private static byte[] loadDigest(File file) throws IOException {
        BufferedReader reader = null;

        try {
            reader = new BufferedReader(new FileReader(getDigestFile(file)));

            String line = reader.readLine();

            if (line == null) {
                throw new ValidationException(file, "invalid digest file");
            }

            int split = line.indexOf(' ');
            String digestHex = line.substring(0, split);
            String fileName = line.substring(split + 2);

            if (!file.getPath().equals(fileName)) {
                throw new ValidationException(file, "invalid digest file");
            }

            return Hex.decodeHex(digestHex.toCharArray());
        } catch (Exception e) {
            throw new ValidationException(file, "invalid digest file");
        } finally {
            if (reader != null) {
                reader.close();
            }
        }
    }

    /**
     * Computes and returns the message digest for the specified file.
     * 
     * @param file the file to be validated
     * @return the message digest for the specified file
     * @throws IOException if an I/O error occurred
     */
    private static byte[] computeDigest(File file) throws IOException {
        InputStream is = null;

        try {
            is = new FileInputStream(file);

            return DigestUtils.md5(is);
        } finally {
            if (is != null) {
                is.close();
            }
        }
    }

    /**
     * Returns a {@link Reader} wrapping the result from calling
     * {@code openInputStream} with the specified file.
     * 
     * @param file the file to be opened
     * @return a {@code Reader} wrapping the result from calling
     *         {@code openInputStream} with the specified file
     * @throws FileNotFoundException if the specified file does not exist
     */
    public static Reader openReader(final File file) throws FileNotFoundException {
        return new InputStreamReader(openInputStream(file));
    }

    /**
     * Returns an {@link InputStream} for reading from the specified file and
     * performs validation on the file when the {@code close} method is invoked
     * on the stream.
     * 
     * @param file the file to the opened and validated
     * @return an {@code InputStream} for reading from the specified file
     * @throws FileNotFoundException if the specified file does not exist
     */
    public static InputStream openInputStream(final File file) throws FileNotFoundException {
        return new DigestInputStream(new FileInputStream(file), createMessageDigest()) {

            @Override
            public void close() throws IOException {
                //finish reading the file contents
                byte[] buffer = new byte[Settings.BUFFER_SIZE];

                while (read(buffer) != -1) {
                    //reading the data calculates the checksum, nothing else to
                    //do here
                }

                super.close();

                //check digest
                validate(file, getMessageDigest().digest());
            }

        };
    }

    /**
     * Returns a {@link Writer} wrapping the result from calling
     * {@code openOutputStream} with the specified file.
     * 
     * @param file the file to be opened
     * @return a {@code Writer} wrapping the result from calling
     *         {@code openOutputStream} with the specified file
     * @throws FileNotFoundException if the specified file does not exist
     */
    public static Writer openWriter(final File file) throws FileNotFoundException {
        return new OutputStreamWriter(openOutputStream(file));
    }

    /**
     * Validates the file.
     * 
     * @param file the file being validated
     * @param actual the actual message digest of the file
     * @throws IOException if an I/O error occurred
     */
    private static void validate(File file, byte[] actual) throws IOException {
        String mode = Settings.getFileProtectionMode();
        File digestFile = getDigestFile(file);

        if (digestFile.exists()) {
            byte[] expected = loadDigest(file);

            if (!MessageDigest.isEqual(actual, expected)) {
                throw new ValidationException(file, "digest does not match");
            }
        } else {
            if (mode.equalsIgnoreCase(STRICT_MODE)) {
                throw new ValidationException(file, "no digest file");
            } else {
                System.err.println("no digest file exists to validate " + file);
            }
        }
    }

    /**
     * Validates the file.
     * 
     * @param file the file to be validated
     * @throws IOException if an I/O error occurred
     */
    public static void validate(File file) throws IOException {
        validate(file, computeDigest(file));
    }

    /**
     * Returns an {@link OutputStream} for writing to the specified file and
     * saves a digest file for validating its contents when the {@code close}
     * method is invoked.
     * 
     * @param file the file to be opened
     * @return an {@code OutputStream} for writing to the specified file
     * @throws FileNotFoundException if the specified file does not exist
     */
    public static OutputStream openOutputStream(final File file) throws FileNotFoundException {
        return new DigestOutputStream(new FileOutputStream(file), createMessageDigest()) {

            @Override
            public void close() throws IOException {
                super.close();

                saveDigest(file, getMessageDigest().digest());
            }

        };
    }

    @SuppressWarnings("static-access")
    @Override
    public Options getOptions() {
        Options options = super.getOptions();

        options.addOption(
                OptionBuilder.withLongOpt("check").withDescription("Validates the listed files").create('c'));

        return options;
    }

    @Override
    public void run(CommandLine commandLine) throws Exception {
        if (commandLine.hasOption("check")) {
            int validCount = 0;
            int invalidCount = 0;
            String mode = Settings.getFileProtectionMode();

            for (String filename : commandLine.getArgs()) {
                File file = new File(filename);

                System.out.print(file);
                System.out.print(": ");

                if (getDigestFile(file).exists()) {
                    byte[] actual = computeDigest(file);
                    byte[] expected = loadDigest(file);
                    boolean valid = MessageDigest.isEqual(actual, expected);

                    if (valid) {
                        validCount++;
                        System.out.println("OK");
                    } else {
                        invalidCount++;
                        System.out.println("FAILED");
                    }
                } else {
                    if (mode.equalsIgnoreCase(STRICT_MODE)) {
                        invalidCount++;
                        System.out.println("FAILED");
                    } else {
                        validCount++;
                        System.out.println("OK (NO DIGEST FILE)");
                    }
                }
            }

            if (invalidCount > 0) {
                System.err.print("WARNING: ");
                System.err.print(invalidCount);
                System.err.print(" of ");
                System.err.print(validCount + invalidCount);
                System.err.println(" computed checksums did NOT match");
            }
        } else {
            for (String filename : commandLine.getArgs()) {
                File file = new File(filename);
                byte[] digest = computeDigest(file);
                saveDigest(file, digest);
            }
        }
    }

    /**
     * Starts the command line utility for validating files using message 
     * digests.
     * 
     * @param args the command line arguments
     * @throws Exception if an error occurred
     */
    public static void main(String[] args) throws Exception {
        new FileProtection().start(args);
    }

}