org.hammurapi.HammurapiArchiver.java Source code

Java tutorial

Introduction

Here is the source code for org.hammurapi.HammurapiArchiver.java

Source

/*
 * Hammurapi
 * Automated Java code review system. 
 * Copyright (C) 2004  Hammurapi Group
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * URL: http://www.hammurapi.org
 * e-Mail: support@hammurapi.biz
    
 */
package org.hammurapi;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.Path;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.pavelvlasov.xml.dom.DOMUtils;

/**
 * Packages source files and classpath entries for Hammurapi review.
 * <section name="Example" suppress-description="yes">
If you copy content of Hammurapi lib directory to ant lib directory then you can
invoke Hammurapi in the following way:
 <pre>&lt;taskdef name="har" classname="org.hammurapi.HammurapiArchiver" /&gt;<br/></pre>
or, if you didn't copy jar files to Ant lib directory, use this syntax:
<pre>&lt;taskdef name="har" classname="org.hammurapi.HammurapiArchiver"&gt;<br/>
<tab/>&lt;classpath&gt;<br/>
    <tab/><tab/>&lt;fileset dir="${hammurapi.home}/lib" includes="*.jar"/&gt;<br/>
<tab/>&lt;/classpath&gt;<br/>
&lt;/taskdef&gt;<br/></pre>
</section>
 * @ant.element name="har" display-name="Packager for automatic code review task"
 * @author Pavel Vlasov   
 * @version $Revision: 1.8 $
 */
public class HammurapiArchiver extends Task {
    static final String DATE_FORMAT = "yyyy/MM/dd HH:mm:ss";

    private Boolean force;

    /**
     * Force review even if the file is not changed
     * @param force
     * @ant.non-required
     */
    public void setForce(boolean force) {
        this.force = force ? Boolean.TRUE : Boolean.FALSE;
    }

    private Boolean forceOnWarnings;

    /**
     * Force review of files with warnings, even if the file is not changed.
     * @ant.non-required
     */
    public void setForceOnWarnings(boolean forceOnWarnings) {
        this.forceOnWarnings = forceOnWarnings ? Boolean.TRUE : Boolean.FALSE;
    }

    private String title;

    /**
     * Review title
     * @ant.non-required
     * @param title
     */
    public void setTitle(String title) {
        this.title = title;
    }

    private File output;

    /**
     * Output archive
     * @ant.required
     * @param output
     */
    public void setOutput(File output) {
        this.output = output;
    }

    /**
     * Classpath for loading classes. Classes and jars from the classpath
     * are packaged into archive to be used during review.
     * @ant:non-required 
     */
    private Path classPath;

    public void setClassPath(Path classPath) {
        if (this.classPath == null) {
            this.classPath = classPath;
        } else {
            this.classPath.append(classPath);
        }
    }

    private Date baseLine;

    /**
     * Date of baseline report
     * @ant.non-required
     * @param baseLine
     */
    public void setBaseLine(Date baseLine) {
        this.baseLine = baseLine;
    }

    private String hostId;

    /**
     * Host id to differentiate archives created on different machines.
     * @ant.non-required 
     */
    public void setHostId(String hostId) {
        this.hostId = hostId;
    }

    //Anu 20050701 start : Added for baselining attribute
    private String baselining;

    public void setBaselining(String baselining) {
        this.baselining = baselining;
    }

    /**
     * Maybe creates a nested classpath element.
     * @ant:non-required
     */
    public Path createClasspath() {
        if (classPath == null) {
            classPath = new Path(project);
        }
        return classPath.createPath();
    }

    private String uniquilize(String name, Set names) {
        int idx = name.lastIndexOf('.');
        String newName = name;
        String ext = "";
        if (idx != -1) {
            ext = name.substring(idx);
            name = name.substring(0, idx);
        }

        for (int i = 0; names.contains(newName.toLowerCase()); i++) {
            newName = name + "_" + Integer.toString(i, Character.MAX_RADIX) + ext;
        }
        names.add(newName.toLowerCase());
        return newName;
    }

    private int zipFile(File in, ZipOutputStream out, String entryName) throws IOException {
        if (in.isFile()) {
            log("Zipping file " + in.getAbsolutePath() + " as " + entryName, Project.MSG_VERBOSE);
            out.putNextEntry(new ZipEntry(entryName));
            byte[] buf = new byte[4096];
            int l;
            FileInputStream fis = new FileInputStream(in);
            while ((l = fis.read(buf)) != -1) {
                out.write(buf, 0, l);
            }
            fis.close();
            out.closeEntry();
            return 1;
        } else if (in.isDirectory()) {
            int ret = 0;
            File[] entries = in.listFiles();
            if (entries != null && entries.length > 0) {
                log("Zipping directory " + in.getAbsolutePath() + " as " + entryName + "/", Project.MSG_VERBOSE);
                out.putNextEntry(new ZipEntry(entryName + "/"));
                for (int i = 0; i < entries.length; i++) {
                    ret += zipFile(entries[i], out, entryName + "/" + entries[i].getName());
                }
                out.closeEntry();
            }
            return ret;
        }

        return 0;
    }

    public void execute() throws BuildException {
        try {
            ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(output));
            Set entryNames = new HashSet();

            Document config = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
            Element root = config.createElement("hammurapi-archive");
            config.appendChild(root);

            if (force != null) {
                root.setAttribute("force", force.booleanValue() ? "yes" : "no");
            }

            if (forceOnWarnings != null) {
                root.setAttribute("force-on-warnings", forceOnWarnings.booleanValue() ? "yes" : "no");
            }

            if (title != null) {
                root.setAttribute("title", title);
            }

            if (reviewDescription != null) {
                root.setAttribute("review-description", reviewDescription);
            }

            if (baseLine != null) {
                root.setAttribute("baseline", new SimpleDateFormat(DATE_FORMAT).format(baseLine));
            }

            if (hostId != null) {
                root.setAttribute("host-id", hostId);
            }

            //Anu 20060701 : Baselining added
            if (baselining != null) {
                root.setAttribute("baselining", baselining);
            }

            Element classPathElement = config.createElement("classpath");
            root.appendChild(classPathElement);

            if (classPath != null) {
                String[] path = classPath.list();
                for (int i = 0; i < path.length; i++) {
                    File cpEntry = new File(path[i]);
                    if (cpEntry.exists() && (cpEntry.isFile() || cpEntry.isDirectory())) {
                        String name = uniquilize("lib/" + cpEntry.getName(), entryNames);
                        if (zipFile(cpEntry, zos, name) > 0) {
                            Element pathElement = config.createElement("path");
                            classPathElement.appendChild(pathElement);
                            pathElement.appendChild(config.createTextNode(name));
                        }
                    } else {
                        log("Classpath entry " + cpEntry.getAbsolutePath() + " does not exist",
                                Project.MSG_VERBOSE);
                    }
                }
            }

            Element sourcesElement = config.createElement("sources");
            root.appendChild(sourcesElement);

            Iterator it = srcFileSets.iterator();
            while (it.hasNext()) {
                HammurapiFileSet fs = (HammurapiFileSet) it.next();
                fs.setDefaultIncludes();
                DirectoryScanner scanner = fs.getDirectoryScanner(project);
                String name = uniquilize("source/" + scanner.getBasedir().getName(), entryNames);
                Element sourceElement = config.createElement("source");
                sourcesElement.appendChild(sourceElement);
                sourceElement.appendChild(config.createTextNode(name));
                String[] files = scanner.getIncludedFiles();
                for (int i = 0; i < files.length; i++) {
                    zipFile(new File(scanner.getBasedir(), files[i]), zos,
                            name + "/" + files[i].replace(File.separatorChar, '/'));
                }
            }

            /**
             * For command-line interface
             */
            it = srcFiles.iterator();
            while (it.hasNext()) {
                String name = uniquilize("source/source", entryNames);
                File file = (File) it.next();
                String entryName = name + "/" + file.getName();
                Element sourceElement = config.createElement("source");
                sourcesElement.appendChild(sourceElement);
                sourceElement.appendChild(config.createTextNode(entryName));
                zipFile(file, zos, entryName);
            }

            ZipEntry configEntry = new ZipEntry("config.xml");
            zos.putNextEntry(configEntry);
            DOMUtils.serialize(config, zos);
            zos.closeEntry();

            zos.close();
        } catch (IOException e) {
            throw new BuildException(e.getMessage(), e);
        } catch (ParserConfigurationException e) {
            throw new BuildException(e.getMessage(), e);
        } catch (FactoryConfigurationError e) {
            throw new BuildException(e.getMessage(), e);
        } catch (TransformerException e) {
            throw new BuildException(e.getMessage(), e);
        }
    }

    /**
     * Source files fileset.
     * @ant.non-required
     */
    public FileSet createSrc() {
        FileSet ret = new HammurapiFileSet("**/*.java");
        srcFileSets.add(ret);
        return ret;
    }

    private List srcFileSets = new LinkedList();

    private Collection srcFiles = new LinkedList();

    private static void printHelpAndExit(Options options) {
        HelpFormatter formatter = new HelpFormatter();
        formatter.printHelp("Usage: har [options] <output file> <source files/dirs>", options, false);
        System.exit(1);
    }

    /**
     * Use it for inspector debugging
     * @param args
     */
    public static void main(String[] args) {
        System.out.println("Hammurapi 3.18.4 Copyright (C) 2004 Hammurapi Group");

        Options options = new Options();

        Option classPathOption = OptionBuilder.withArgName("classpath").hasArg().withDescription("ClassPath")
                .isRequired(false).create("c");

        options.addOption(classPathOption);

        Option hostIdOption = OptionBuilder.withArgName("hostId").hasArg().withDescription("Host id")
                .isRequired(false).create("H");

        options.addOption(hostIdOption);

        Option titleOption = OptionBuilder.withArgName("title").hasArg().withDescription("Report title")
                .isRequired(false).create("T");

        options.addOption(titleOption);

        Option baseLineOption = OptionBuilder.withDescription("Baseline date").withArgName("date").hasArg()
                .isRequired(false).create("n");

        options.addOption(baseLineOption);

        Option forceOption = OptionBuilder.withDescription("Force reviews on unchanged files").isRequired(false)
                .create("f");

        options.addOption(forceOption);

        Option forceOnWarningsOption = OptionBuilder.withDescription("Do not force reviews of files with warnings")
                .isRequired(false).create("k");

        options.addOption(forceOnWarningsOption);

        Option descriptionOption = OptionBuilder.withDescription("Review description").withArgName("description")
                .hasArg().isRequired(false).create("y");
        options.addOption(descriptionOption);

        //Anu :20050701 Added baselining parameter
        Option baseliningOption = OptionBuilder.withArgName("off|on|set").hasArg()
                .withDescription("Baselining mode").isRequired(false).create("B");

        options.addOption(descriptionOption);

        Option helpOption = OptionBuilder.withDescription("Print this message").isRequired(false).create("h");
        options.addOption(helpOption);

        CommandLineParser parser = new PosixParser();
        CommandLine line = null;
        try {
            line = parser.parse(options, args);
        } catch (ParseException e) {
            System.err.println(e.getMessage());
            System.err.flush();
            printHelpAndExit(options);
        }

        if (line.hasOption("h")) {
            printHelpAndExit(options);
        }

        HammurapiArchiver task = new HammurapiArchiver();
        Project project = new Project();
        task.setProject(project);
        project.setCoreLoader(task.getClass().getClassLoader());

        String[] values = line.getOptionValues('c');
        for (int i = 0; values != null && i < values.length; i++) {
            task.createClasspath().append(new Path(project, values[i]));
        }

        String[] largs = line.getArgs();
        if (largs.length == 0) {
            System.out.println("Output file has to be provided");
            printHelpAndExit(options);
        }

        if (line.hasOption('f')) {
            task.setForce(true);
        }

        if (line.hasOption('k')) {
            task.setForceOnWarnings(false);
        }

        if (line.hasOption('n')) {
            task.setBaseLine(new Date(line.getOptionValue('n')));
        }

        if (line.hasOption('H')) {
            task.setHostId(line.getOptionValue('H'));
        }

        if (line.hasOption('y')) {
            task.setReviewDescription(line.getOptionValue('y'));
        }

        if (line.hasOption('T')) {
            task.setTitle(line.getOptionValue('T'));
        }

        //Anu :20050701 Added for Baselining attribute
        if (line.hasOption('B')) {
            task.setBaselining(line.getOptionValue('B'));
        }

        task.setOutput(new File(largs[0]));

        for (int i = 1; i < largs.length; i++) {
            File file = new File(largs[i]);
            if (file.isFile()) {
                task.srcFiles.add(file);
            } else if (file.isDirectory()) {
                task.createSrc().setDir(file);
            }
        }

        task.setTaskName("har");

        try {
            task.execute();
            System.exit(0);
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(2);
        }
    }

    private String reviewDescription;

    /**
     * Description of review, e.g. release number. Appears in history annotation.
     * @ant.non-required
     */
    public void setReviewDescription(String reviewDescription) {
        this.reviewDescription = reviewDescription;
    }

}