Package org.apache.tools.ant.taskdefs.optional

Source Code of org.apache.tools.ant.taskdefs.optional.IContract$ClasspathHelper

/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2001-2003 The Apache Software Foundation.  All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in
*    the documentation and/or other materials provided with the
*    distribution.
*
* 3. The end-user documentation included with the redistribution, if
*    any, must include the following acknowlegement:
*       "This product includes software developed by the
*        Apache Software Foundation (http://www.apache.org/)."
*    Alternately, this acknowlegement may appear in the software itself,
*    if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "Ant" and "Apache Software
*    Foundation" must not be used to endorse or promote products derived
*    from this software without prior written permission. For written
*    permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
*    nor may "Apache" appear in their names without prior written
*    permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation.  For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.tools.ant.taskdefs.optional;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Date;
import java.util.Properties;
import org.apache.tools.ant.BuildEvent;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.BuildListener;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.Java;
import org.apache.tools.ant.taskdefs.Javac;
import org.apache.tools.ant.taskdefs.MatchingTask;
import org.apache.tools.ant.taskdefs.Mkdir;
import org.apache.tools.ant.taskdefs.compilers.DefaultCompilerAdapter;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.Reference;

/**
* Instruments Java classes with iContract DBC preprocessor.
* <br/>
* The task can generate a properties file for
* <a href="http://hjem.sol.no/hellesoy/icontrol.html">iControl</a>,
* a graphical user interface that lets you turn on/off assertions.
* iControl generates a control file that you can refer to
* from this task using the controlfile attribute.
* iContract is at
* <a href="http://www.reliable-systems.com/tools/">
*   http://www.reliable-systems.com/tools/</a>
* <p/>
* Thanks to Rainer Schmitz for enhancements and comments.
*
* @author <a href="mailto:aslak.hellesoy@bekk.no">Aslak Helles\u00f8y</a>
*
* <p/>
* <table border="1" cellpadding="2" cellspacing="0">
*   <tr>
*     <td valign="top"><b>Attribute</b></td>
*     <td valign="top"><b>Description</b></td>
*     <td align="center" valign="top"><b>Required</b></td>
*   </tr>
*   <tr>
*     <td valign="top">srcdir</td>
*     <td valign="top">Location of the java files.</td>
*     <td valign="top" align="center">Yes</td>
*   </tr>
*   <tr>
*     <td valign="top">instrumentdir</td>
*     <td valign="top">Indicates where the instrumented source
*                      files should go.</td>
*     <td valign="top" align="center">Yes</td>
*   </tr>
*   <tr>
*     <td valign="top">repositorydir</td>
*     <td valign="top">Indicates where the repository source
*                      files should go.</td>
*     <td valign="top" align="center">Yes</td>
*   </tr>
*   <tr>
*     <td valign="top">builddir</td>
*     <td valign="top">Indicates where the compiled instrumented
*                      classes should go. Defaults to the value of
*                      instrumentdir.
*       </p>
*       <em>NOTE:</em> Don't use the same directory for compiled
*       instrumented classes and uninstrumented classes. It will break the
*       dependency checking. (Classes will not be reinstrumented if you
*       change them).</td>
*     <td valign="top" align="center">No</td>
*   </tr>
*   <tr>
*     <td valign="top">repbuilddir</td>
*     <td valign="top">Indicates where the compiled repository classes
*                      should go. Defaults to the value of repositorydir.</td>
*     <td valign="top" align="center">No</td>
*   </tr>
*   <tr>
*     <td valign="top">pre</td>
*     <td valign="top">Indicates whether or not to instrument for
*                      preconditions. Defaults to <code>true</code> unless
*                      controlfile is specified, in which case it defaults
*                      to <code>false</code>.</td>
*     <td valign="top" align="center">No</td>
*   </tr>
*   <tr>
*     <td valign="top">post</td>
*     <td valign="top">Indicates whether or not to instrument for
*                      postconditions. Defaults to <code>true</code> unless
*                      controlfile is specified, in which case it defaults
*                      to <code>false</code>.</td>
*     <td valign="top" align="center">No</td>
*   </tr>
*   <tr>
*     <td valign="top">invariant</td>
*     <td valign="top">Indicates whether or not to instrument for invariants.
*                      Defaults to <code>true</code> unless controlfile is
*                      specified, in which case it defaults to
*                      <code>false</code>.</td>
*     <td valign="top" align="center">No</td>
*   </tr>
*   <tr>
*     <td valign="top">failthrowable</td>
*     <td valign="top">The full name of the Throwable (Exception) that
*                      should be thrown when an assertion is violated.
*                      Defaults to <code>java.lang.Error</code></td>
*     <td valign="top" align="center">No</td>
*   </tr>
*   <tr>
*     <td valign="top">verbosity</td>
*     <td valign="top">Indicates the verbosity level of iContract.
*       Any combination of
*       <code>error*,warning*,note*,info*,progress*,debug*</code>
*       (comma separated) can be used. Defaults to <code>error*</code></td>
*     <td valign="top" align="center">No</td>
*   </tr>
*   <tr>
*     <td valign="top">quiet</td>
*     <td valign="top">Indicates if iContract should be quiet. Turn it off
*       if many your classes extend uninstrumented classes and you don't
*       want warnings about this. Defaults to <code>false</code></td>
*     <td valign="top" align="center">No</td>
*   </tr>
*   <tr>
*     <td valign="top">updateicontrol</td>
*     <td valign="top">If set to true, it indicates that the properties
*       file for iControl in the current directory should be updated
*       (or created if it doesn't exist). Defaults to <code>false</code>.
*     </td>
*     <td valign="top" align="center">No</td>
*   </tr>
*   <tr>
*     <td valign="top">controlfile</td>
*     <td valign="top">The name of the control file to pass to iContract.
*                      Consider using iControl to generate the file.
*                      Default is not to pass a file. </td>
*     <td valign="top" align="center">
*                      Only if <code>updateicontrol=true</code></td>
*   </tr>
*   <tr>
*     <td valign="top">classdir</td>
*     <td valign="top">Indicates where compiled (unistrumented) classes are
*                      located. This is required in order to properly update
*                      the icontrol.properties file, not for instrumentation.
*     </td>
*     <td valign="top" align="center">Only if
*                                     <code>updateicontrol=true</code></td>
*   </tr>
*   <tr>
*     <td valign="top">targets</td>
*     <td valign="top">Name of the file that will be generated by this task,
*                      which lists all the classes that iContract will
*                      instrument. If specified, the file will not be deleted
*                      after execution. If not specified, a file will still
*                      be created, but it will be deleted after execution.</td>
*     <td valign="top" align="center">No</td>
*   </tr>
* </table>
*
* <p/>
* <b>Note:</b> iContract will use the java compiler indicated by the project's
* <code>build.compiler</code> property. See documentation of the Javac task for
* more information.
* <p/>
* Nested includes and excludes are also supported.
*
* <p><b>Example:</b></p>
* <pre>
* &lt;icontract
*    srcdir="${build.src}"
*    instrumentdir="${build.instrument}"
*    repositorydir="${build.repository}"
*    builddir="${build.instrclasses}"
*    updateicontrol="true"
*    classdir="${build.classes}"
*    controlfile="control"
*    targets="targets"
*    verbosity="error*,warning*"
*    quiet="true"
* >
*    &lt;classpath refid="compile-classpath"/>
* &lt;/icontract>
* </pre>
*
*/
public class IContract extends MatchingTask {

    private static final String ICONTROL_PROPERTIES_HEADER
        = "You might want to set classRoot to point to your normal "
            + "compilation class root directory.";

    /** compiler to use for instrumenation */
    private String icCompiler = "javac";

    /** temporary file with file names of all java files to be instrumented */
    private File targets = null;

    /**
     * will be set to true if any of the source files are newer than the
     * instrumented files
     */
    private boolean dirty = false;

    /** set to true if the iContract jar is missing */
    private boolean iContractMissing = false;

    /** source file root */
    private File srcDir = null;

    /** instrumentation src root */
    private File instrumentDir = null;

    /** instrumentation build root */
    private File buildDir = null;

    /** repository src root */
    private File repositoryDir = null;

    /** repository build root */
    private File repBuildDir = null;

    /** classpath */
    private Path classpath = null;

    /** The class of the Throwable to be thrown on failed assertions */
    private String failThrowable = "java.lang.Error";

    /** The -v option */
    private String verbosity = "error*";

    /** The -q option */
    private boolean quiet = false;

    /** The -m option */
    private File controlFile = null;

    /** Indicates whether or not to instrument for preconditions */
    private boolean pre = true;
    private boolean preModified = false;

    /** Indicates whether or not to instrument for postconditions */
    private boolean post = true;
    private boolean postModified = false;

    /** Indicates whether or not to instrument for invariants */
    private boolean invariant = true;
    private boolean invariantModified = false;

    /**
     * Indicates whether or not to instrument all files regardless of timestamp
     *
     * Can't be explicitly set, is set if control file exists and is newer
     * than any source file
     */
    private boolean instrumentall = false;

    /**
     * Indicates the name of a properties file (intentionally for iControl)
     * where the classpath property should be updated.
     */
    private boolean updateIcontrol = false;

    /** Regular compilation class root  */
    private File classDir = null;

    /**
     * Sets the source directory.
     *
     * @param srcDir the source directory
     */
    public void setSrcdir(File srcDir) {
        this.srcDir = srcDir;
    }


    /**
     * Sets the class directory (uninstrumented classes).
     *
     * @param classDir the source directory
     */
    public void setClassdir(File classDir) {
        this.classDir = classDir;
    }


    /**
     * Sets the instrumentation directory.
     *
     * @param instrumentDir the source directory
     */
    public void setInstrumentdir(File instrumentDir) {
        this.instrumentDir = instrumentDir;
        if (this.buildDir == null) {
            setBuilddir(instrumentDir);
        }
    }


    /**
     * Sets the build directory for instrumented classes.
     *
     * @param buildDir the build directory
     */
    public void setBuilddir(File buildDir) {
        this.buildDir = buildDir;
    }


    /**
     * Sets the build directory for repository classes.
     *
     * @param repositoryDir the source directory
     */
    public void setRepositorydir(File repositoryDir) {
        this.repositoryDir = repositoryDir;
        if (this.repBuildDir == null) {
            setRepbuilddir(repositoryDir);
        }
    }


    /**
     * Sets the build directory for instrumented classes.
     *
     * @param repBuildDir the build directory
     */
    public void setRepbuilddir(File repBuildDir) {
        this.repBuildDir = repBuildDir;
    }


    /**
     * Turns on/off precondition instrumentation.
     *
     * @param pre true turns it on
     */
    public void setPre(boolean pre) {
        this.pre = pre;
        preModified = true;
    }


    /**
     * Turns on/off postcondition instrumentation.
     *
     * @param post true turns it on
     */
    public void setPost(boolean post) {
        this.post = post;
        postModified = true;
    }


    /**
     * Turns on/off invariant instrumentation.
     *
     * @param invariant true turns it on
     */
    public void setInvariant(boolean invariant) {
        this.invariant = invariant;
        invariantModified = true;
    }


    /**
     * Sets the Throwable (Exception) to be thrown on assertion violation.
     *
     * @param clazz the fully qualified Throwable class name
     */
    public void setFailthrowable(String clazz) {
        this.failThrowable = clazz;
    }


    /**
     * Sets the verbosity level of iContract. Any combination of
     * error*,warning*,note*,info*,progress*,debug* (comma separated) can be
     * used. Defaults to error*,warning*
     *
     * @param verbosity verbosity level
     */
    public void setVerbosity(String verbosity) {
        this.verbosity = verbosity;
    }


    /**
     * Tells iContract to be quiet.
     *
     * @param quiet true if iContract should be quiet.
     */
    public void setQuiet(boolean quiet) {
        this.quiet = quiet;
    }


    /**
     * Sets the name of the file where targets will be written. That is the
     * file that tells iContract what files to process.
     *
     * @param targets the targets file name
     */
    public void setTargets(File targets) {
        this.targets = targets;
    }


    /**
     * Sets the control file to pass to iContract.
     *
     * @param controlFile the control file
     */
    public void setControlfile(File controlFile) {
        if (!controlFile.exists()) {
            log("WARNING: Control file " + controlFile.getAbsolutePath()
                 + " doesn't exist. iContract will be run "
                 + "without control file.");
        }
        this.controlFile = controlFile;
    }


    /**
     * Sets the classpath to be used for invocation of iContract.
     *
     * @param path the classpath
     */
    public void setClasspath(Path path) {
        createClasspath().append(path);
    }


    /**
     * Sets the classpath.
     *
     * @return the nested classpath element
     * @todo this overwrites the classpath so only one
     *       effective classpath element would work. This
     *       is not how we do this elsewhere.
     */
    public Path createClasspath() {
        if (classpath == null) {
            classpath = new Path(getProject());
        }
        return classpath;
    }


    /**
     * Adds a reference to a classpath defined elsewhere.
     *
     * @param reference referenced classpath
     */
    public void setClasspathRef(Reference reference) {
        createClasspath().setRefid(reference);
    }


    /**
     * If true, updates iControl properties file
     *
     * @param updateIcontrol true if iControl properties file should be
     *      updated
     */
    public void setUpdateicontrol(boolean updateIcontrol) {
        this.updateIcontrol = updateIcontrol;
    }


    /**
     * Executes the task
     *
     * @exception BuildException if the instrumentation fails
     */
    public void execute() throws BuildException {
        preconditions();
        scan();
        if (dirty) {

            // turn off assertions if we're using controlfile, unless they are not explicitly set.
            boolean useControlFile = (controlFile != null) && controlFile.exists();

            if (useControlFile && !preModified) {
                pre = false;
            }
            if (useControlFile && !postModified) {
                post = false;
            }
            if (useControlFile && !invariantModified) {
                invariant = false;
            }
            // issue warning if pre,post or invariant is used together with controlfile
            if ((pre || post || invariant) && controlFile != null) {
                log("WARNING: specifying pre,post or invariant will "
                     + "override control file settings");
            }


            // We want to be notified if iContract jar is missing.
            // This makes life easier for the user who didn't understand
            // that iContract is a separate library (duh!)
            getProject().addBuildListener(new IContractPresenceDetector());

            // Prepare the directories for iContract. iContract will make
            // them if they don't exist, but for some reason I don't know,
            // it will complain about the REP files afterwards
            Mkdir mkdir = (Mkdir) getProject().createTask("mkdir");

            mkdir.setDir(instrumentDir);
            mkdir.execute();
            mkdir.setDir(buildDir);
            mkdir.execute();
            mkdir.setDir(repositoryDir);
            mkdir.execute();

            // Set the classpath that is needed for regular Javac compilation
            Path baseClasspath = createClasspath();

            // Might need to add the core classes if we're not using
            // Sun's Javac (like Jikes)
            String compiler = getProject().getProperty("build.compiler");
            ClasspathHelper classpathHelper = new ClasspathHelper(compiler);

            classpathHelper.modify(baseClasspath);

            // Create the classpath required to compile the sourcefiles
            // BEFORE instrumentation
            Path beforeInstrumentationClasspath = ((Path) baseClasspath.clone());

            beforeInstrumentationClasspath.append(new Path(getProject(),
                srcDir.getAbsolutePath()));

            // Create the classpath required to compile the sourcefiles
            // AFTER instrumentation
            Path afterInstrumentationClasspath = ((Path) baseClasspath.clone());

            afterInstrumentationClasspath.append(new Path(getProject(),
                instrumentDir.getAbsolutePath()));
            afterInstrumentationClasspath.append(new Path(getProject(),
                repositoryDir.getAbsolutePath()));
            afterInstrumentationClasspath.append(new Path(getProject(),
                srcDir.getAbsolutePath()));
            afterInstrumentationClasspath.append(new Path(getProject(),
                buildDir.getAbsolutePath()));

            // Create the classpath required to automatically compile the
            // repository files
            Path repositoryClasspath = ((Path) baseClasspath.clone());

            repositoryClasspath.append(new Path(getProject(),
                instrumentDir.getAbsolutePath()));
            repositoryClasspath.append(new Path(getProject(),
                srcDir.getAbsolutePath()));
            repositoryClasspath.append(new Path(getProject(),
                repositoryDir.getAbsolutePath()));
            repositoryClasspath.append(new Path(getProject(),
                buildDir.getAbsolutePath()));

            // Create the classpath required for iContract itself
            Path iContractClasspath = ((Path) baseClasspath.clone());

            iContractClasspath.append(new Path(getProject(),
                System.getProperty("java.home") + File.separator + ".."
                    + File.separator + "lib" + File.separator + "tools.jar"));
            iContractClasspath.append(new Path(getProject(),
                srcDir.getAbsolutePath()));
            iContractClasspath.append(new Path(getProject(),
                repositoryDir.getAbsolutePath()));
            iContractClasspath.append(new Path(getProject(),
                instrumentDir.getAbsolutePath()));
            iContractClasspath.append(new Path(getProject(),
                buildDir.getAbsolutePath()));

            // Create a forked java process
            Java iContract = (Java) getProject().createTask("java");

            iContract.setTaskName(getTaskName());
            iContract.setFork(true);
            iContract.setClassname("com.reliablesystems.iContract.Tool");
            iContract.setClasspath(iContractClasspath);

            // Build the arguments to iContract
            StringBuffer args = new StringBuffer();

            args.append(directiveString());
            args.append("-v").append(verbosity).append(" ");

            args.append("-b").append("\"").append(icCompiler);
            args.append(" -classpath ").append(beforeInstrumentationClasspath);
            args.append("\" ");

            args.append("-c").append("\"").append(icCompiler);
            args.append(" -classpath ").append(afterInstrumentationClasspath);
            args.append(" -d ").append(buildDir).append("\" ");

            args.append("-n").append("\"").append(icCompiler);
            args.append(" -classpath ").append(repositoryClasspath);
            args.append("\" ");

            args.append("-d").append(failThrowable).append(" ");

            args.append("-o").append(instrumentDir).append(File.separator);
            args.append("@p").append(File.separator).append("@f.@e ");

            args.append("-k").append(repositoryDir).append(File.separator);
            args.append("@p ");

            args.append(quiet ? "-q " : "");
            // reinstrument everything if controlFile exists and is newer
            // than any class
            args.append(instrumentall ? "-a " : "");
            args.append("@").append(targets.getAbsolutePath());
            iContract.createArg().setLine(args.toString());

            //System.out.println( "JAVA -classpath " + iContractClasspath
            //    + " com.reliablesystems.iContract.Tool " + args.toString() );

            // update iControlProperties if it's set.
            if (updateIcontrol) {
                Properties iControlProps = new Properties();

                try {
                    // to read existing propertiesfile
                    iControlProps.load(new FileInputStream("icontrol.properties"));
                } catch (IOException e) {
                    log("File icontrol.properties not found. That's ok. "
                        + "Writing a default one.");
                }
                iControlProps.setProperty("sourceRoot",
                    srcDir.getAbsolutePath());
                iControlProps.setProperty("classRoot",
                    classDir.getAbsolutePath());
                iControlProps.setProperty("classpath",
                    afterInstrumentationClasspath.toString());
                iControlProps.setProperty("controlFile",
                    controlFile.getAbsolutePath());
                iControlProps.setProperty("targetsFile",
                    targets.getAbsolutePath());

                try {
                    // to read existing propertiesfile
                    iControlProps.store(new FileOutputStream("icontrol.properties"),
                        ICONTROL_PROPERTIES_HEADER);
                    log("Updated icontrol.properties");
                } catch (IOException e) {
                    log("Couldn't write icontrol.properties.");
                }
            }

            // do it!
            int result = iContract.executeJava();

            if (result != 0) {
                if (iContractMissing) {
                    log("iContract can't be found on your classpath. "
                        + "Your classpath is:");
                    log(classpath.toString());
                    log("If you don't have the iContract jar, go get it at "
                        + "http://www.reliable-systems.com/tools/");
                }
                throw new BuildException("iContract instrumentation failed. "
                    + "Code = " + result);
            }
        } else {
            // not dirty
            //log( "Nothing to do. Everything up to date." );
        }
    }


    /** Checks that the required attributes are set.  */
    private void preconditions() throws BuildException {
        if (srcDir == null) {
            throw new BuildException("srcdir attribute must be set!",
                getLocation());
        }
        if (!srcDir.exists()) {
            throw new BuildException("srcdir \"" + srcDir.getPath()
                + "\" does not exist!", getLocation());
        }
        if (instrumentDir == null) {
            throw new BuildException("instrumentdir attribute must be set!",
                getLocation());
        }
        if (repositoryDir == null) {
            throw new BuildException("repositorydir attribute must be set!",
                getLocation());
        }
        if (updateIcontrol && classDir == null) {
            throw new BuildException("classdir attribute must be specified "
                + "when updateicontrol=true!", getLocation());
        }
        if (updateIcontrol && controlFile == null) {
            throw new BuildException("controlfile attribute must be specified "
                + "when updateicontrol=true!", getLocation());
        }
    }


    /**
     * Verifies whether any of the source files have changed. Done by
     * comparing date of source/class files. The whole lot is "dirty" if at
     * least one source file or the control file is newer than the
     * instrumented files. If not dirty, iContract will not be executed. <br/>
     * Also creates a temporary file with a list of the source files, that
     * will be deleted upon exit.
     */
    private void scan() throws BuildException {
        long now = (new Date()).getTime();

        DirectoryScanner ds = null;

        ds = getDirectoryScanner(srcDir);

        String[] files = ds.getIncludedFiles();

        FileOutputStream targetOutputStream = null;
        PrintStream targetPrinter = null;
        boolean writeTargets = false;

        try {
            if (targets == null) {
                targets = new File("targets");
                log("Warning: targets file not specified. generating file: "
                    + targets.getName());
                writeTargets = true;
            } else if (!targets.exists()) {
                log("Specified targets file doesn't exist. generating file: "
                    + targets.getName());
                writeTargets = true;
            }
            if (writeTargets) {
                log("You should consider using iControl to create a target file.");
                targetOutputStream = new FileOutputStream(targets);
                targetPrinter = new PrintStream(targetOutputStream);
            }
            for (int i = 0; i < files.length; i++) {
                File srcFile = new File(srcDir, files[i]);

                if (files[i].endsWith(".java")) {
                    // print the target, while we're at here. (Only if generatetarget=true).
                    if (targetPrinter != null) {
                        targetPrinter.println(srcFile.getAbsolutePath());
                    }
                    File classFile
                        = new File(buildDir, files[i].substring(0, files[i].indexOf(".java")) + ".class");

                    if (srcFile.lastModified() > now) {
                        log("Warning: file modified in the future: "
                            + files[i], Project.MSG_WARN);
                    }

                    if (!classFile.exists() || srcFile.lastModified() > classFile.lastModified()) {
                        //log( "Found a file newer than the instrumentDir class file: "
                        //    + srcFile.getPath() + " newer than " + classFile.getPath()
                        //    + ". Running iContract again..." );
                        dirty = true;
                    }
                }
            }
            if (targetPrinter != null) {
                targetPrinter.flush();
                targetPrinter.close();
            }
        } catch (IOException e) {
            throw new BuildException("Could not create target file:" + e.getMessage());
        }

        // also, check controlFile timestamp
        long controlFileTime = -1;

        try {
            if (controlFile != null) {
                if (controlFile.exists() && buildDir.exists()) {
                    controlFileTime = controlFile.lastModified();
                    ds = getDirectoryScanner(buildDir);
                    files = ds.getIncludedFiles();
                    for (int i = 0; i < files.length; i++) {
                        File srcFile = new File(srcDir, files[i]);

                        if (files[i].endsWith(".class")) {
                            if (controlFileTime > srcFile.lastModified()) {
                                if (!dirty) {
                                    log("Control file "
                                        + controlFile.getAbsolutePath()
                                        + " has been updated. "
                                        + "Instrumenting all files...");
                                }
                                dirty = true;
                                instrumentall = true;
                            }
                        }
                    }
                }
            }
        } catch (Throwable t) {
            throw new BuildException("Got an interesting exception:"
                + t.getMessage());
        }
    }


    /**
     * Creates the -m option based on the values of controlFile, pre, post and
     * invariant.
     */
    private final String directiveString() {
        StringBuffer sb = new StringBuffer();
        boolean comma = false;

        boolean useControlFile = (controlFile != null) && controlFile.exists();

        if (useControlFile || pre || post || invariant) {
            sb.append("-m");
        }
        if (useControlFile) {
            sb.append("@").append(controlFile);
            comma = true;
        }
        if (pre) {
            if (comma) {
                sb.append(",");
            }
            sb.append("pre");
            comma = true;
        }
        if (post) {
            if (comma) {
                sb.append(",");
            }
            sb.append("post");
            comma = true;
        }
        if (invariant) {
            if (comma) {
                sb.append(",");
            }
            sb.append("inv");
        }
        sb.append(" ");
        return sb.toString();
    }


    /**
     * BuildListener that sets the iContractMissing flag to true if a message
     * about missing iContract is missing. Used to indicate a more verbose
     * error to the user, with advice about how to solve the problem
     *
     * @author Conor MacNeill
     */
    private class IContractPresenceDetector implements BuildListener {
        public void buildFinished(BuildEvent event) {
        }


        public void buildStarted(BuildEvent event) {
        }


        public void messageLogged(BuildEvent event) {
            if ("java.lang.NoClassDefFoundError: com/reliablesystems/iContract/Tool".equals(event.getMessage())) {
                iContractMissing = true;
            }
        }


        public void targetFinished(BuildEvent event) {
        }


        public void targetStarted(BuildEvent event) {
        }


        public void taskFinished(BuildEvent event) {
        }


        public void taskStarted(BuildEvent event) {
        }
    }


    /**
     * This class is a helper to set correct classpath for other compilers,
     * like Jikes. It reuses the logic from DefaultCompilerAdapter, which is
     * protected, so we have to subclass it.
     *
     * @author Conor MacNeill
     */
    private class ClasspathHelper extends DefaultCompilerAdapter {
        private final String compiler;


        public ClasspathHelper(String compiler) {
            super();
            this.compiler = compiler;
        }

        // make it public
        public void modify(Path path) {
            // depending on what compiler to use, set the
            // includeJavaRuntime flag
            if ("jikes".equals(compiler)) {
                icCompiler = compiler;
                includeJavaRuntime = true;
                path.append(getCompileClasspath());
            }
        }

        // dummy implementation. Never called
        public void setJavac(Javac javac) {
        }


        public boolean execute() {
            return true;
        }
    }
}

TOP

Related Classes of org.apache.tools.ant.taskdefs.optional.IContract$ClasspathHelper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.