edu.ksu.cis.indus.tools.slicer.SliceXMLizerCLI.java Source code

Java tutorial

Introduction

Here is the source code for edu.ksu.cis.indus.tools.slicer.SliceXMLizerCLI.java

Source

/*******************************************************************************
 * Indus, a program analysis and transformation toolkit for Java.
 * Copyright (c) 2001, 2007 Venkatesh Prasad Ranganath
 * 
 * All rights reserved.  This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 which accompanies 
 * the distribution containing this program, and is available at 
 * http://www.opensource.org/licenses/eclipse-1.0.php.
 * 
 * For questions about the license, copyright, and software, contact 
 *    Venkatesh Prasad Ranganath at venkateshprasad.ranganath@gmail.com
 *                                 
 * This software was developed by Venkatesh Prasad Ranganath in SAnToS Laboratory 
 * at Kansas State University.
 *******************************************************************************/

package edu.ksu.cis.indus.tools.slicer;

import edu.ksu.cis.indus.common.collections.IPredicate;
import edu.ksu.cis.indus.common.collections.MapUtils;
import edu.ksu.cis.indus.common.scoping.SpecificationBasedScopeDefinition;
import edu.ksu.cis.indus.common.soot.ApplicationClassesOnlyPredicate;
import edu.ksu.cis.indus.common.soot.IStmtGraphFactory;
import edu.ksu.cis.indus.common.soot.MetricsProcessor;
import edu.ksu.cis.indus.common.soot.SootBasedDriver;
import edu.ksu.cis.indus.interfaces.IEnvironment;
import edu.ksu.cis.indus.processing.Environment;
import edu.ksu.cis.indus.processing.IProcessingFilter;
import edu.ksu.cis.indus.processing.OneAllStmtSequenceRetriever;
import edu.ksu.cis.indus.processing.ProcessingController;
import edu.ksu.cis.indus.processing.TagBasedProcessingFilter;
import edu.ksu.cis.indus.slicer.ISliceCriterion;
import edu.ksu.cis.indus.slicer.transformations.TagBasedDestructiveSliceResidualizer;
import edu.ksu.cis.indus.staticanalyses.tokens.ITokens;
import edu.ksu.cis.indus.staticanalyses.tokens.TokenUtil;
import edu.ksu.cis.indus.staticanalyses.tokens.soot.SootValueTypeManager;
import edu.ksu.cis.indus.tools.IToolProgressListener;
import edu.ksu.cis.indus.tools.Phase;
import edu.ksu.cis.indus.tools.slicer.criteria.generators.LineNumberBasedCriteriaGenerator;
import edu.ksu.cis.indus.tools.slicer.criteria.generators.StmtTypeBasedSliceCriteriaGenerator;
import edu.ksu.cis.indus.tools.slicer.criteria.predicates.AbstractSliceCriteriaPredicate;
import edu.ksu.cis.indus.tools.slicer.criteria.specification.SliceCriteriaParser;
import edu.ksu.cis.indus.xmlizer.AbstractXMLizer;
import edu.ksu.cis.indus.xmlizer.IJimpleIDGenerator;
import edu.ksu.cis.indus.xmlizer.IXMLizer;
import edu.ksu.cis.indus.xmlizer.UniqueJimpleIDGenerator;
import edu.ksu.cis.indus.xmlizer.XMLizingProcessingFilter;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.cli.BasicParser;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.jibx.runtime.JiBXException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import soot.Printer;
import soot.SootClass;
import soot.SootMethod;
import soot.Type;
import soot.Value;
import soot.jimple.Stmt;
import soot.jimple.ThrowStmt;

/**
 * This is the command-line driver class for the slicer tool.
 * 
 * @author <a href="http://www.cis.ksu.edu/~rvprasad">Venkatesh Prasad Ranganath</a>
 * @author $Author: rvprasad $
 * @version $Revision: 1.98 $ $Date: 2009/11/30 20:04:03 $
 */
public class SliceXMLizerCLI extends SootBasedDriver implements IToolProgressListener {

    /**
     * This predicate allows only one statement to be considered as a criterion.
     * 
     * @author <a href="http://www.cis.ksu.edu/~rvprasad">Venkatesh Prasad Ranganath</a>
     * @author $Author: rvprasad $
     * @version $Revision: 1.98 $ $Date: 2009/11/30 20:04:03 $
     */
    private class CustomCriteriaPredicate extends AbstractSliceCriteriaPredicate<Stmt> {

        /**
         * This indicates if the predicate is counting. Only in counting status will the predicate accept criteria.
         */
        private boolean countingStatus = true;

        /**
         * The collection of statements that have been considered as criterion.
         */
        private final Collection<Stmt> stmts;

        /**
         * Creates an instance of this class.
         */
        CustomCriteriaPredicate() {
            super();
            stmts = new HashSet<Stmt>();
        }

        /**
         * {@inheritDoc}
         */
        public boolean evaluate(final Stmt t) {
            final boolean _flag;
            if (countingStatus) {
                _flag = stmts.add(t);
                if (_flag) {
                    countingStatus = false;
                }
            } else {
                _flag = false;
            }
            return _flag;
        }

        /**
         * Retrieves the number of slices generated so far.
         * 
         * @return the number of slices.
         */
        int getSliceCount() {
            return stmts.size();
        }

        /**
         * Sets the predicate into counting status.
         */
        void setCountingStatus() {
            countingStatus = true;
        }
    }

    /**
     * The logger used by instances of this class to log messages.
     */
    static final Logger LOGGER = LoggerFactory.getLogger(SliceXMLizerCLI.class);

    /**
     * This is the name of the configuration file to use.
     */
    private static String configFileName;

    /**
     * This specifies the scope of the slice.
     */
    private static SpecificationBasedScopeDefinition sliceScope;

    /**
     * This is the name of the directory into which the slicer will dump sliced artifacts into.
     */
    protected String outputDirectory;

    /**
     * The instance of the slicer tool.
     */
    SlicerTool<?> slicer;

    /**
     * This directory into which jimple should be dumped.
     */
    String jimpleXMLDumpDir;

    /**
     * This is the names of the classes that need to be retained when optimizing the slice for space.
     */
    private Collection<String> retentionList;

    /**
     * The id generator used during xmlization.
     */
    private IJimpleIDGenerator idGenerator;

    /**
     * The name of the criteria specification file.
     */
    private String criteriaSpecFileName;

    /**
     * The line based criteria generator.
     */
    private LineNumberBasedCriteriaGenerator lineBasedCriteriaGenerator;

    /**
     * This is the name of the tag to be used to tag parts of the AST occurring in the slice.
     */
    private final String nameOfSliceTag = "indus.tools.slicer.SliceXMLizerCLI:SLICER";

    /**
     * This indicates if jimple representation of the system after residualiztion should be dumped.
     */
    private boolean postResJimpleDump;

    /**
     * This indicates if jimple representation of the system after residualiztion should be dumped in XML form.
     */
    private boolean postResXMLJimpleDump;

    /**
     * This indicates if jimple representation of the system after slicing and before residualization should be dumped.
     */
    private boolean preResJimpleDump;

    /**
     * This indicates if jimple representation of the system after slicing and before residualiztion should be dumped in XML
     * form.
     */
    private boolean preResXMLJimpleDump;

    /**
     * This indicates if the slice should be residualized.
     */
    private boolean residualize;

    /**
     * This indicates if the xml representation of the slice should be generated.
     */
    private boolean shouldWriteSliceXML;

    /**
     * This indicates if the slice should preserve every "throw" statements.
     */
    private boolean preserveThrowStmtsInAppClassesOnly;

    /**
     * This indicates if a separate slice should be generated for each "throwstatement.
     */
    private boolean generateSeparateSlicesForEachThrowStmt;

    /**
     * This indicates if detailed (or summarized) stats should be provided.
     */
    private boolean detailedStats;

    /**
     * This indicates if the slice should preserve every "throw" statements.
     */
    private boolean preserveThrowStatements;

    /**
     * Creates an instance of this class.
     * 
     * @param <T> is the type of tokens used in the flow analysis of the slicer. This is a dummy parameter.
     */
    protected <T extends ITokens<T, Value>> SliceXMLizerCLI() {
        slicer = new SlicerTool<T>(TokenUtil.<T, Value, Type>getTokenManager(new SootValueTypeManager()),
                getStmtGraphFactory());
        cfgProvider = slicer.getStmtGraphFactory();
    }

    /**
     * The entry point to the driver.
     * 
     * @param args contains the command line arguments.
     */
    public static void main(final String[] args) {
        final SliceXMLizerCLI _xmlizer = new SliceXMLizerCLI();

        // parse command line arguments
        parseCommandLine(args, _xmlizer);

        _xmlizer.initialize();

        if (!_xmlizer.generateSeparateSlicesForEachThrowStmt) {
            final long _startTime = System.currentTimeMillis();

            _xmlizer.executeForSingleSlice();

            final long _stopTime = System.currentTimeMillis();

            if (LOGGER.isInfoEnabled()) {
                LOGGER.info("It took " + (_stopTime - _startTime) + "ms to identify the slice.");
            }

            _xmlizer.setIDGenerator(new UniqueJimpleIDGenerator());
            _xmlizer.writeSliceXML();
            _xmlizer.outputStats(_xmlizer.nameOfSliceTag);
            _xmlizer.residualize();
            _xmlizer.slicer.reset();
            _xmlizer.reset();
        } else {
            _xmlizer.executeForMultipleSlices();
        }
    }

    /**
     * {@inheritDoc}
     * 
     * @see IToolProgressListener#toolProgess(IToolProgressListener.ToolProgressEvent)
     */
    public void toolProgess(final ToolProgressEvent evt) {
        if (LOGGER.isInfoEnabled()) {
            LOGGER.info(evt.getMsg() + " - " + evt.getInfo());
        }
    }

    /**
     * Sets the configuration to be used.
     * 
     * @param configuration is the stringized form of the slicer configuration.
     * @pre configuration != null
     */
    protected final void setConfiguration(final String configuration) {
        slicer.destringizeConfiguration(configuration);
    }

    /**
     * Retrieves the xmlizer to be used to xmlizer the slice.
     * 
     * @return the slice xmlizer.
     * @post result != null
     */
    protected final TagBasedSliceXMLizer getXMLizer() {
        return new TagBasedSliceXMLizer(nameOfSliceTag, idGenerator);
    }

    /**
     * Sets the id generator to use during xmlization.
     * 
     * @param generator used to generate the id's during xmlization.
     * @pre generator != null
     */
    protected void setIDGenerator(final IJimpleIDGenerator generator) {
        idGenerator = generator;
    }

    /**
     * Sets the output directory into which files should be dumped.
     * 
     * @param oDir is the output directory.
     * @pre oDir != null
     */
    protected final void setOutputDirectory(final String oDir) {
        outputDirectory = oDir;
    }

    /**
     * Executes the slicer to generate multiple slices -- one for each throw statement. The slice will not be residualized in
     * this mode.
     */
    private void executeForMultipleSlices() {
        final StmtTypeBasedSliceCriteriaGenerator _generator = new StmtTypeBasedSliceCriteriaGenerator();
        _generator.setStmtTypes(Collections.singleton(ThrowStmt.class));

        if (preserveThrowStmtsInAppClassesOnly) {
            _generator.setSiteSelectionPredicate(new ApplicationClassesOnlyPredicate());
        }

        final CustomCriteriaPredicate _filter = new CustomCriteriaPredicate();

        _generator.setCriteriaFilterPredicate(_filter);
        slicer.addCriteriaGenerator(_generator);

        // execute the slicer
        final Collection<ISliceCriterion> _criteria = processCriteriaSpecFile();
        slicer.addCriteria(_criteria);
        slicer.setSystem(new Environment(scene));
        slicer.setRootMethods(rootMethods);
        slicer.setSliceScopeDefinition(sliceScope);
        slicer.addToolProgressListener(this);

        slicer.setTagName(nameOfSliceTag);
        slicer.run(Phase.STARTING_PHASE, SlicerTool.SLICE_MAJOR_PHASE, true);

        int _prevSize;
        int _count = 0;
        do {
            _prevSize = _filter.getSliceCount();
            final String _tag = nameOfSliceTag + ":" + _prevSize;
            slicer.setTagName(_tag);
            slicer.run(SlicerTool.SLICE_MAJOR_PHASE, Phase.FINISHED_PHASE, true);
            outputStats(_tag);
            dumpJimple("_" + String.valueOf(_count++), true, false, _tag);
            _filter.setCountingStatus();
            if (LOGGER.isInfoEnabled()) {
                try {
                    LOGGER.info("Criteria specification after slicing: \n"
                            + SliceCriteriaParser.serialize(slicer.getCriteria()));
                } catch (final JiBXException _e) {
                    LOGGER.info("JiBX failed during serialization.", _e);
                }
            }
        } while (_filter.getSliceCount() == _count);
    }

    /**
     * Executes the slicer to generate a slice.
     */
    void executeForSingleSlice() {
        // execute the slicer
        slicer.setTagName(nameOfSliceTag);
        slicer.setSystem(new Environment(scene));
        slicer.setRootMethods(rootMethods);

        if (preserveThrowStatements) {
            final StmtTypeBasedSliceCriteriaGenerator _generator = new StmtTypeBasedSliceCriteriaGenerator();
            _generator.setStmtTypes(Collections.singleton(ThrowStmt.class));
            if (preserveThrowStmtsInAppClassesOnly) {
                _generator.setSiteSelectionPredicate(new IPredicate<SootMethod>() {

                    public boolean evaluate(final SootMethod t) {
                        return t.getDeclaringClass().isApplicationClass();
                    }
                });
            }
            slicer.addCriteriaGenerator(_generator);
        }

        if (lineBasedCriteriaGenerator != null) {
            slicer.addCriteriaGenerator(lineBasedCriteriaGenerator);
        }

        slicer.setSliceScopeDefinition(sliceScope);

        final Collection<ISliceCriterion> _criteria = processCriteriaSpecFile();
        slicer.addCriteria(_criteria);
        slicer.addToolProgressListener(this);
        slicer.run(Phase.STARTING_PHASE, null, true);

        if (LOGGER.isInfoEnabled()) {
            try {
                LOGGER.info("Criteria specification after slicing: \n"
                        + SliceCriteriaParser.serialize(slicer.getCriteria()));
            } catch (final JiBXException _e) {
                LOGGER.info("JiBX failed during serialization.", _e);
            }
        }
    }

    /**
     * Processing for line based criteria specification.
     * 
     * @param lineBasedCritSpecFileName is the file containing the line based criteria specificaiton.
     */
    private void setLineBasedCriteriaSpecFile(final String lineBasedCritSpecFileName) {
        try {
            final InputStream _io = new FileInputStream(new File(lineBasedCritSpecFileName));
            final Properties _props = new Properties();
            _props.load(_io);
            lineBasedCriteriaGenerator = new LineNumberBasedCriteriaGenerator(_props);
            soot.options.Options.v().set_keep_line_number(true);
        } catch (final IOException _e) {
            lineBasedCriteriaGenerator = null;
            LOGGER.error("Error while handling line based criteria spec file", _e);
            throw new IllegalArgumentException("Error while handling line based criteria spec file", _e);
        }
    }

    /**
     * Updates jimple destructively.
     */
    void destructivelyUpdateJimple() {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Residualizing");
        }

        final TagBasedDestructiveSliceResidualizer _residualizer = new TagBasedDestructiveSliceResidualizer();
        _residualizer.setTagToResidualize(nameOfSliceTag);
        _residualizer.setBasicBlockGraphMgr(getBbm());
        _residualizer.residualizeSystem(getEnvironment());
    }

    /**
     * Dump xmlized jimple.
     * 
     * @param base from which the names of the jimple file will be built.
     * @pre base != null
     */
    void dumpJimpleAsXML(final String base) {
        final IXMLizer _xmlizer = getXMLizer();

        if (jimpleXMLDumpDir != null) {
            if (LOGGER.isInfoEnabled()) {
                LOGGER.info("BEGIN: Dumping XMLized Jimple");
            }

            final ProcessingController _ctrl = new ProcessingController();
            final IProcessingFilter _filter = new XMLizingProcessingFilter();
            final OneAllStmtSequenceRetriever _ssr = new OneAllStmtSequenceRetriever();
            _ssr.setStmtGraphFactory(getStmtGraphFactory());
            _ctrl.setStmtSequencesRetriever(_ssr);
            _ctrl.setEnvironment(getEnvironment());
            _filter.chain(new TagBasedProcessingFilter(nameOfSliceTag));
            _ctrl.setProcessingFilter(_filter);
            ((AbstractXMLizer) _xmlizer).dumpJimple(base, jimpleXMLDumpDir, _ctrl);

            if (LOGGER.isInfoEnabled()) {
                LOGGER.info("END: Dumping XMLized Jimple");
            }
        }
    }

    /**
     * Parses the command line argument.
     * 
     * @param args contains the command line arguments.
     * @param xmlizer used to xmlize the slice.
     * @pre args != null and xmlizer != null
     */
    private static void parseCommandLine(final String[] args, final SliceXMLizerCLI xmlizer) {
        // create options
        final Options _options = new Options();
        Option _o = new Option("c", "config-file", true,
                "The configuration file to use.  If unspecified, uses default configuration file.");
        _o.setArgs(1);
        _o.setArgName("config-file");
        _o.setOptionalArg(false);
        _options.addOption(_o);
        _o = new Option("a", "active-config", true,
                "The alternate configuration to use instead of the one specified in the configuration.");
        _o.setArgs(1);
        _o.setArgName("config");
        _o.setLongOpt("active-config");
        _o.setOptionalArg(false);
        _options.addOption(_o);
        _o = new Option("o", "output-dir", true,
                "The output directory to dump the generated info.  If unspecified, picks a temporary directory.");
        _o.setArgs(1);
        _o.setArgName("path");
        _o.setOptionalArg(false);
        _options.addOption(_o);
        _o = new Option("g", "gui-config", false, "Display gui for configuration.");
        _o.setOptionalArg(false);
        _options.addOption(_o);
        _o = new Option("p", "soot-classpath", true, "Prepend this to soot class path.");
        _o.setArgs(1);
        _o.setArgName("classpath");
        _o.setOptionalArg(false);
        _options.addOption(_o);
        _o = new Option("e", "exception-preserving-slice", true,
                "Generate slice that preserves every throw statement in "
                        + "the application class. Comma-separated combination of optional arguments: inAppOnly - preserve throw "
                        + "statements in application classes only, separateSlices - generated a different slice for each throw "
                        + "statement. **This option should not be combined with -r**");
        _o.setArgs(1);
        _o.setOptionalArg(true);
        _o.setArgName("applClassOnly");
        _options.addOption(_o);
        _o = new Option(" ", "detailedStats", false, "Display detailed stats.");
        _o.setOptionalArg(false);
        _o = new Option("h", "help", false, "Display message.");
        _o.setOptionalArg(false);
        _options.addOption(_o);
        _o = new Option("i", "output-xml-jimple-before-res", false,
                "Output xml representation of the jimple BEFORE residualization.");
        _o.setOptionalArg(false);
        _options.addOption(_o);
        _o = new Option("j", "output-xml-jimple-after-res", false,
                "Output xml representation of the jimple AFTER residualization. This only works with -r option.");
        _o.setOptionalArg(false);
        _options.addOption(_o);
        _o = new Option("I", "output-jimple-before-res", false, "Output jimple BEFORE residualization.");
        _o.setOptionalArg(false);
        _options.addOption(_o);
        _o = new Option("J", "output-jimple-after-res", false,
                "Output jimple AFTER residualization. This only works with -r option.");
        _o.setOptionalArg(false);
        _options.addOption(_o);
        _o = new Option("s", "criteria-spec-file", true, "Use the slice criteria specified in this file.");
        _o.setArgs(1);
        _o.setArgName("crit-spec-file");
        _o.setOptionalArg(false);
        _options.addOption(_o);
        _o = new Option("sa", "Perform scoped analysis (as opposed merely performing scoped slicing)");
        _options.addOption(_o);
        _o = new Option("S", "slice-scope-spec-file", true, "Use the scope specified in this file.");
        _o.setArgs(1);
        _o.setArgName("slice-scope-spec-file");
        _o.setOptionalArg(false);
        _options.addOption(_o);
        _o = new Option("r", "residualize", true,
                "Residualize after slicing. This will also dump the class files for the residualized classes.  Provide the "
                        + "name of the file as an optional argument to optimize the slice (via transformation) for space.  The file should"
                        + "contain the FQN of classes (1 per line) to be retained during optimization.");
        _o.setOptionalArg(true);
        _options.addOption(_o);
        _o = new Option("x", "output-slice-xml", false, "Output xml representation of the slice.");
        _o.setOptionalArg(false);
        _options.addOption(_o);
        _o = new Option("l", true, "Generate criteria based on line number based criteria spec file. The format is "
                + "<class FQN>=<comma-separated list of line numbers from the class containing  Java file>.");
        _o.setArgs(1);
        _o.setArgName("line-based-criteria-spec-file");
        _o.setOptionalArg(false);
        _options.addOption(_o);

        CommandLine _cl = null;

        // parse the arguments
        Exception _exception = null;

        try {
            _cl = (new BasicParser()).parse(_options, args);
        } catch (ParseException _e) {
            _exception = _e;
        }

        if (_exception != null || _cl.hasOption("h")) {
            printUsage(_options);

            if (_exception != null) {
                LOGGER.error("Incorrect command line.  Aborting.", _exception);
                System.exit(1);
            } else {
                System.exit(0);
            }
        }
        xmlizer.setConfiguration(processCommandLineForConfiguration(_cl));
        setupOutputOptions(_cl, xmlizer);

        if (_cl.hasOption('p')) {
            xmlizer.addToSootClassPath(_cl.getOptionValue('p'));
        }

        if (_cl.hasOption('a')) {
            xmlizer.setConfigName(_cl.getOptionValue('a'));
        }

        if (_cl.hasOption('g')) {
            xmlizer.showGUI();
        }

        if (_cl.hasOption('s')) {
            xmlizer.setSliceCriteriaSpecFile(_cl.getOptionValue('s'));
        }

        if (_cl.hasOption('r')) {
            xmlizer.setResidulization(true);

            final String _optionValue = _cl.getOptionValue('r');

            if (_optionValue != null) {
                xmlizer.extractExclusionListForCompaction(_optionValue);
            }
        }

        if (_cl.hasOption('S')) {
            sliceScope = xmlizer.setScopeSpecFile(_cl.getOptionValue('S'));
            if (_cl.hasOption("sa")) {
                xmlizer.setScopeSpecFile(_cl.getOptionValue('S'));
            } else {
                xmlizer.setScopeSpecFile(null);
            }
        }

        if (_cl.hasOption('l')) {
            xmlizer.setLineBasedCriteriaSpecFile(_cl.getOptionValue('l'));
        }

        xmlizer.preserveThrowStatements = _cl.hasOption('e');
        if (xmlizer.preserveThrowStatements) {
            xmlizer.parseThrowStmtTreatmentOptions(_cl.getOptionValue('e'));
        }

        if (xmlizer.generateSeparateSlicesForEachThrowStmt && xmlizer.residualize) {
            throw new IllegalArgumentException(
                    "Residualization (-r) cannot be combined multiple slice generation mode (-e separateSlices).");
        }

        xmlizer.detailedStats = _cl.hasOption("detailedStats");

        xmlizer.shouldWriteSliceXML = _cl.hasOption('x');

        final List<String> _result = _cl.getArgList();

        if (_result.isEmpty()) {
            LOGGER.error(
                    "Please specify atleast one class that contains an entry method into the system to be sliced.");
            System.exit(1);
        }

        xmlizer.setClassNames(_result);
    }

    /**
     * Process the arguments to the "process throw statement" option.
     * 
     * @param optionValue to be processed.
     */
    private void parseThrowStmtTreatmentOptions(final String optionValue) {
        if (optionValue == null) {
            return;
        }

        final String[] _values = optionValue.split(",");
        for (final String _v : _values) {
            if (_v.equals("appClassOnly")) {
                preserveThrowStmtsInAppClassesOnly = true;
            } else if (_v.equals("separateSlices")) {
                generateSeparateSlicesForEachThrowStmt = true;
            }
        }
    }

    /**
     * Extracts the FQN of classes that need to retained in the system when optimizing the slice for space.
     * 
     * @param fileName obviously.
     * @pre fileName != null
     */
    private void extractExclusionListForCompaction(final String fileName) {
        retentionList = new ArrayList<String>();

        try {
            final BufferedReader _br = new BufferedReader(new FileReader(new File(fileName)));

            while (_br.ready()) {
                retentionList.add(_br.readLine());
            }
            _br.close();
        } catch (final FileNotFoundException _e) {
            LOGGER.error(
                    "File does not exists - " + fileName + ". Hence the slice will not be optimized for space.",
                    _e);
            retentionList = null;
        } catch (final IOException _e) {
            LOGGER.error(
                    "Error reading the file - " + fileName + ". Hence the slice will not be optimized for space.",
                    _e);
            retentionList = null;
        }
    }

    /**
     * Prints the help/usage info for this class.
     * 
     * @param options is the command line option.
     * @pre options != null
     */
    private static void printUsage(final Options options) {
        final String _cmdLineSyn = "java " + SliceXMLizerCLI.class.getName() + " <options> <classnames>";
        (new HelpFormatter()).printHelp(_cmdLineSyn, "Options are: ", options, "");
    }

    /**
     * Processes the command line for slicer tool configuration information. Defaults to a configuration if none are
     * specified.
     * 
     * @param cl is the parsed command line.
     * @return the tool configuration as a string.
     * @post result != null
     * @pre cl != null
     */
    private static String processCommandLineForConfiguration(final CommandLine cl) {
        final String _config = cl.getOptionValue('c');
        configFileName = _config;
        return SlicerToolHelper.loadConfigurationInFile(_config);
    }

    /**
     * Sets up the output options according to the command line args.
     * 
     * @param cl contains the command line.
     * @param xmlizer that needs to be configured.
     * @pre cl != null and xmlizer != null
     */
    private static void setupOutputOptions(final CommandLine cl, final SliceXMLizerCLI xmlizer) {
        final String _outputDir;

        if (cl.hasOption('o')) {
            _outputDir = cl.getOptionValue("o");
        } else {
            final File _tempDir = new File(
                    System.getProperty("java.io.tmpdir") + File.separator + System.currentTimeMillis() + "_slicer");
            _tempDir.mkdirs();
            _outputDir = _tempDir.getAbsolutePath();

            if (LOGGER.isWarnEnabled()) {
                LOGGER.warn("Using " + _outputDir + " as the directory to dump information");
            }
        }

        xmlizer.preResXMLJimpleDump = cl.hasOption('i');
        xmlizer.postResXMLJimpleDump = cl.hasOption('j') && cl.hasOption('r');
        xmlizer.preResJimpleDump = cl.hasOption('I');
        xmlizer.postResJimpleDump = cl.hasOption('J') && cl.hasOption('r');

        if (xmlizer.preResXMLJimpleDump || xmlizer.postResXMLJimpleDump || xmlizer.preResJimpleDump
                || xmlizer.postResJimpleDump) {
            xmlizer.jimpleXMLDumpDir = _outputDir;
        }

        xmlizer.setOutputDirectory(_outputDir);
    }

    /**
     * Changes the active configuration to use.
     * 
     * @param configID is the id of the active configuration.
     * @pre configID != null
     */
    private void setConfigName(final String configID) {
        slicer.setActiveConfiguration(configID);
    }

    /**
     * Sets if the slice should be residualized.
     * 
     * @param flag <code>true</code> indicates the slice should be residualized; <code>false</code>, otherwise.
     */
    private void setResidulization(final boolean flag) {
        residualize = flag;
    }

    /**
     * Sets the name of the file containing the slice criteria specification.
     * 
     * @param fileName of the slice criteria spec.
     * @pre fileName != null
     */
    private void setSliceCriteriaSpecFile(final String fileName) {
        criteriaSpecFileName = fileName;
    }

    /**
     * Dumps jimple for the classes in the scene. The jimple file names will end with the given suffix.
     * 
     * @param suffix to be appended to the file name.
     * @param jimpleFile <code>true</code> indicates that class files should be dumped as well; <code>false</code>,
     *            otherwise.
     * @param classFile <code>true</code> indicates that class files should be dumped as well; <code>false</code>,
     *            otherwise.
     * @param tag to jimplify.
     */
    private void dumpJimple(final String suffix, final boolean jimpleFile, final boolean classFile,
            final String tag) {
        final Printer _printer = Printer.v();

        for (@SuppressWarnings("unchecked")
        final Iterator<SootClass> _i = scene.getClasses().iterator(); _i.hasNext();) {
            final SootClass _sc = _i.next();

            if (!_sc.hasTag(tag)) {
                continue;
            }

            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Dumping jimple for " + _sc + " with suffix " + suffix);
            }

            for (@SuppressWarnings("unchecked")
            final Iterator<SootMethod> _j = _sc.getMethods().iterator(); _j.hasNext();) {
                final SootMethod _sm = _j.next();

                if (_sm.isConcrete()) {
                    try {
                        _sm.retrieveActiveBody();
                    } catch (final RuntimeException _e) {
                        LOGGER.error("Failed to retrieve body for method " + _sm, _e);
                    }
                }
            }

            PrintWriter _writer = null;

            try {
                // write .jimple file
                if (jimpleFile) {
                    final File _file = new File(
                            outputDirectory + File.separator + _sc.getName() + ".jimple" + suffix);
                    _writer = new PrintWriter(new FileWriter(_file));
                    _printer.printTo(_sc, _writer);
                }

                // write .class file
                if (classFile) {
                    _printer.write(_sc, outputDirectory);
                }
            } catch (final IOException _e) {
                LOGGER.error("Error while writing " + _sc, _e);
            } catch (final RuntimeException _e) {
                LOGGER.error("Error while writing class file of " + _sc, _e);
            } finally {
                if (_writer != null) {
                    _writer.flush();
                    _writer.close();
                }
            }
        }
    }

    /**
     * Outputs the statistics for the system.
     * 
     * @param tag identifies the slice to process.
     */
    private void outputStats(final String tag) {
        if (LOGGER.isInfoEnabled()) {
            final MetricsProcessor _processor = new MetricsProcessor();
            final ProcessingController _pc = new ProcessingController();
            final OneAllStmtSequenceRetriever _ssr = new OneAllStmtSequenceRetriever();
            _ssr.setStmtGraphFactory(getStmtGraphFactory());
            _pc.setStmtSequencesRetriever(_ssr);
            _pc.setEnvironment(getEnvironment());
            _pc.setProcessingFilter(new TagBasedProcessingFilter(SlicerTool.FLOW_ANALYSIS_TAG_NAME));
            _processor.hookup(_pc);
            _pc.process();
            _processor.unhook(_pc);

            LOGGER.info("PRE SLICING STATISTICS:"
                    + MapUtils.verbosePrint(detailedStats ? _processor.getStatistics() : _processor.getSummary()));

            _pc.setProcessingFilter(new TagBasedProcessingFilter(tag));
            _processor.hookup(_pc);
            _pc.setEnvironment(new Environment(scene));
            _pc.process();
            _processor.unhook(_pc);

            LOGGER.info("POST SLICING STATISTICS:"
                    + MapUtils.verbosePrint(detailedStats ? _processor.getStatistics() : _processor.getSummary()));
        }
    }

    /**
     * Process the criteria specification file.
     * 
     * @return a collection of criteria
     * @throws IllegalArgumentException when the errors occur while accessing the specified file.
     * @throws IllegalStateException when the parsing of the specified file fails.
     */
    private Collection<ISliceCriterion> processCriteriaSpecFile()
            throws IllegalArgumentException, IllegalStateException {
        final Collection<ISliceCriterion> _criteria = new HashSet<ISliceCriterion>();

        if (criteriaSpecFileName != null) {
            try {
                final InputStream _in = new FileInputStream(criteriaSpecFileName);
                final String _result = IOUtils.toString(_in);
                IOUtils.closeQuietly(_in);

                final String _criteriaSpec = _result;
                _criteria.addAll(SliceCriteriaParser.deserialize(_criteriaSpec, scene));

                if (LOGGER.isInfoEnabled()) {
                    LOGGER.info("Criteria specification before slicing: \n" + _result);
                    LOGGER.info("Criteria before slicing: \n" + _criteria);
                }
            } catch (final IOException _e) {
                if (LOGGER.isWarnEnabled()) {
                    final String _msg = "Error retrieved slicing criteria from " + criteriaSpecFileName;
                    LOGGER.error(_msg, _e);

                    final IllegalArgumentException _i = new IllegalArgumentException(_msg);
                    _i.initCause(_e);
                    throw _i;
                }
            } catch (final JiBXException _e) {
                if (LOGGER.isWarnEnabled()) {
                    final String _msg = "JiBX failed during deserialization.";
                    LOGGER.error(_msg, _e);

                    final IllegalStateException _i = new IllegalStateException(_msg);
                    _i.initCause(_e);
                    throw _i;
                }
            }
        }
        return _criteria;
    }

    /**
     * Residualize the slice as jimple files in the output directory.
     */
    private void residualize() {
        if (preResXMLJimpleDump) {
            dumpJimpleAsXML("unsliced");
        }

        if (preResJimpleDump) {
            dumpJimple("_preRes", true, false, nameOfSliceTag);
        }

        if (residualize) {
            if (retentionList != null) {
                SlicerToolHelper.optimizeForSpaceBeforeResidualization(slicer, retentionList);
            }
            destructivelyUpdateJimple();

            if (retentionList != null) {
                final Collection<SootClass> _c = SlicerToolHelper.optimizeForSpaceAfterResidualization(slicer,
                        retentionList);

                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("Retained classes are " + _c);
                }
            }
            dumpJimple("", false, true, nameOfSliceTag);
        }

        if (postResJimpleDump) {
            dumpJimple("_postRes", true, false, nameOfSliceTag);
        }

        if (postResXMLJimpleDump) {
            dumpJimpleAsXML("sliced");
        }
    }

    /**
     * Displays the tool configuration GUI.
     */
    private void showGUI() {
        // call the configurator on the slicer
        final Display _display = new Display();
        final Shell _shell = new Shell(SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL);
        _shell.setText("Slicer configuration");

        // create a composite for the configurator to display information.
        final RowLayout _rowLayout = new RowLayout();
        _rowLayout.type = SWT.VERTICAL;
        _shell.setLayout(_rowLayout);
        slicer.getConfigurator().initialize(new Composite(_shell, SWT.NONE));

        // add a OK button to close the window.
        final Button _ok = new Button(_shell, SWT.PUSH);
        _ok.setText("Ok");
        _ok.addSelectionListener(new SelectionListener() {

            public void widgetSelected(@SuppressWarnings("unused") final SelectionEvent evt) {
                _shell.dispose();
            }

            public void widgetDefaultSelected(final SelectionEvent evt) {
                widgetSelected(evt);
            }
        });
        _shell.layout();
        _shell.pack();
        _shell.open();

        while (!_shell.isDisposed()) {
            if (!_display.readAndDispatch()) {
                _display.sleep();
            }
        }
        _display.dispose();

        // save the configuration
        try {
            if (configFileName != null) {
                FileUtils.writeStringToFile(new File(configFileName), slicer.stringizeConfiguration(), "UTF-8");
            } else {
                if (LOGGER.isWarnEnabled()) {
                    LOGGER.warn("Configuration file name is unspecified.  Printing to console.");
                }
                System.out.println(slicer.stringizeConfiguration());
            }
        } catch (IOException _e) {
            if (LOGGER.isWarnEnabled()) {
                LOGGER.warn("Could not write the configuration file.  Printing to console", _e);
            }
            System.out.println(slicer.stringizeConfiguration());
        }
    }

    /**
     * Write the slice as XML document.
     */
    private void writeSliceXML() {
        if (shouldWriteSliceXML) {
            // serialize the output of the slicer
            final IXMLizer _xmlizer = getXMLizer();
            final Map<Object, Object> _info = new HashMap<Object, Object>();

            _info.put(IEnvironment.ID, getEnvironment());
            _info.put(IStmtGraphFactory.ID, getStmtGraphFactory());
            _xmlizer.setXmlOutputDir(outputDirectory);
            _xmlizer.writeXML(_info);
        }
    }
}

// End of File