net.sf.clirr.cli.Clirr.java Source code

Java tutorial

Introduction

Here is the source code for net.sf.clirr.cli.Clirr.java

Source

//////////////////////////////////////////////////////////////////////////////
// Clirr: compares two versions of a java library for binary compatibility
// Copyright (C) 2003 - 2013  Lars Khne
//
// This library 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 2.1 of the License, or (at your option) any later version.
//
// This library 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 this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//////////////////////////////////////////////////////////////////////////////

package net.sf.clirr.cli;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;

import net.sf.clirr.core.Checker;
import net.sf.clirr.core.CheckerException;
import net.sf.clirr.core.ClassSelector;
import net.sf.clirr.core.DiffListener;
import net.sf.clirr.core.PlainDiffListener;
import net.sf.clirr.core.XmlDiffListener;
import net.sf.clirr.core.spi.DefaultTypeArrayBuilderFactory;
import net.sf.clirr.core.spi.JavaType;
import net.sf.clirr.core.spi.Scope;
import net.sf.clirr.core.spi.TypeArrayBuilder;

import org.apache.commons.cli.BasicParser;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;

/**
 * Command line interface for generating a difference report or checking
 * for binary compatibility between two versions of the same application.
 */

public final class Clirr {
    private Clirr() {
    }

    public static void main(String[] args) {
        new Clirr().run(args);
    }

    // ===================================================================

    private void run(String[] args) {
        Options options = defineOptions();

        CommandLine cmdline = parseCommandLine(args, options);

        String oldPath = cmdline.getOptionValue('o');
        String newPath = cmdline.getOptionValue('n');
        String oldClassPath = cmdline.getOptionValue("ocp");
        String newClassPath = cmdline.getOptionValue("ncp");
        String style = cmdline.getOptionValue('s', "text");
        String outputFileName = cmdline.getOptionValue('f');
        String[] includePkgs = cmdline.getOptionValues('i');
        boolean showAll = cmdline.hasOption('a');
        boolean showPkg = cmdline.hasOption('p');

        if ((oldPath == null) || (newPath == null)) {
            printUsage(options, System.err);
            System.exit(-1);
        }

        Checker checker = new Checker();
        if (showAll) {
            checker.getScopeSelector().setScope(Scope.PRIVATE);
        } else if (showPkg) {
            checker.getScopeSelector().setScope(Scope.PACKAGE);
        }

        ClassSelector classSelector;
        if ((includePkgs != null) && (includePkgs.length > 0)) {
            classSelector = new ClassSelector(ClassSelector.MODE_IF);
            for (int i = 0; i < includePkgs.length; ++i) {
                classSelector.addPackageTree(includePkgs[i]);
            }
        } else {
            // a selector that selects everything
            classSelector = new ClassSelector(ClassSelector.MODE_UNLESS);
        }

        DiffListener diffListener = null;
        if (style.equals("text")) {
            try {
                diffListener = new PlainDiffListener(outputFileName);
            } catch (IOException ex) {
                System.err.println("Invalid output file name.");
            }
        } else if (style.equals("xml")) {
            try {
                diffListener = new XmlDiffListener(outputFileName);
            } catch (IOException ex) {
                System.err.println("Invalid output file name.");
            }
        } else {
            System.err.println("Invalid style option. Must be one of 'text', 'xml'.");
            printUsage(options, System.err);
            System.exit(-1);
        }

        File[] origClassPathEntries = pathToFileArray(oldPath);
        File[] newClassPathEntries = pathToFileArray(newPath);

        checker.addDiffListener(diffListener);

        try {
            ClassLoader loader1 = new URLClassLoader(convertFilesToURLs(pathToFileArray(oldClassPath)));
            ClassLoader loader2 = new URLClassLoader(convertFilesToURLs(pathToFileArray(newClassPath)));

            DefaultTypeArrayBuilderFactory tabFactory = new DefaultTypeArrayBuilderFactory();

            TypeArrayBuilder tab1 = tabFactory.build();
            TypeArrayBuilder tab2 = tabFactory.build();

            final JavaType[] origClasses = tab1.createClassSet(origClassPathEntries, loader1, classSelector);

            final JavaType[] newClasses = tab2.createClassSet(newClassPathEntries, loader2, classSelector);

            checker.reportDiffs(origClasses, newClasses);

            System.exit(0);
        } catch (CheckerException ex) {
            System.err.println("Unable to complete checks: " + ex.getMessage());
            System.exit(1);
        } catch (MalformedURLException ex) {
            System.err.println("Unable to create classloader for 3rd party classes: " + ex.getMessage());
            System.err.println("old classpath: " + oldClassPath);
            System.err.println("new classpath: " + newClassPath);
            System.exit(1);
        } catch (RuntimeException ex) {
            System.err.println("Unable to complete checks: " + ex.toString());
            Throwable cause = ex.getCause();
            if (cause != null) {
                System.err.println("  caused by : " + cause.toString());
            }
            System.exit(2);
        }
    }

    private CommandLine parseCommandLine(String[] args, Options options) {
        BasicParser parser = new BasicParser();
        CommandLine cmdline = null;
        try {
            cmdline = parser.parse(options, args);
        } catch (ParseException ex) {
            System.err.println("Invalid command line arguments.");
            printUsage(options, System.err);
            System.exit(-1);
        }
        return cmdline;
    }

    private Options defineOptions() {
        Options options = new Options();
        options.addOption("o", "old-version", true, "jar files of old version");
        options.addOption("n", "new-version", true, "jar files of new version");
        options.addOption("ocp", "orig-classpath", true, "3rd party classpath that is referenced by old-version");
        options.addOption("ncp", "new-classpath", true, "3rd party classpath that is referenced by new-version");
        options.addOption("s", "style", true, "output style [text|xml]");
        options.addOption("i", "include-pkg", true, "include only classes from this package and its subpackages");
        options.addOption("p", "show-pkg-scope", false, "show package scope classes");
        options.addOption("a", "show-all-scopes", false, "show private and package classes");
        options.addOption("f", "output-file", true, "output file name");
        return options;
    }

    private void printUsage(Options options, OutputStream os) {
        HelpFormatter hf = new HelpFormatter();
        PrintWriter out = new PrintWriter(os);
        hf.printHelp(out, 75, "java " + getClass().getName() + " -o path -n path [options]", null, options,
                HelpFormatter.DEFAULT_LEFT_PAD, HelpFormatter.DEFAULT_DESC_PAD, null);
        out.flush();
    }

    private File[] pathToFileArray(String path) {
        if (path == null) {
            return new File[0];
        }

        ArrayList files = new ArrayList();

        int pos = 0;
        while (pos < path.length()) {
            int colonPos = path.indexOf(File.pathSeparatorChar, pos);
            if (colonPos == -1) {
                files.add(new File(path.substring(pos)));
                break;
            }

            files.add(new File(path.substring(pos, colonPos)));
            pos = colonPos + 1;
        }

        return (File[]) files.toArray(new File[files.size()]);
    }

    private URL[] convertFilesToURLs(File[] files) throws MalformedURLException {
        URL[] ret = new URL[files.length];
        for (int i = 0; i < files.length; i++) {
            ret[i] = files[i].toURI().toURL();
        }
        return ret;
    }
}