Clover coverage report - Ant Coverage
Coverage timestamp: Tue Apr 8 2003 20:43:55 EST
file stats: LOC: 889   Methods: 33
NCLOC: 378   Classes: 3
 
 Source file Conditionals Statements Methods TOTAL
IContract.java 0% 0% 0% 0%
 1   
 /*
 2   
  * The Apache Software License, Version 1.1
 3   
  *
 4   
  * Copyright (c) 2001-2002 The Apache Software Foundation.  All rights
 5   
  * reserved.
 6   
  *
 7   
  * Redistribution and use in source and binary forms, with or without
 8   
  * modification, are permitted provided that the following conditions
 9   
  * are met:
 10   
  *
 11   
  * 1. Redistributions of source code must retain the above copyright
 12   
  *    notice, this list of conditions and the following disclaimer.
 13   
  *
 14   
  * 2. Redistributions in binary form must reproduce the above copyright
 15   
  *    notice, this list of conditions and the following disclaimer in
 16   
  *    the documentation and/or other materials provided with the
 17   
  *    distribution.
 18   
  *
 19   
  * 3. The end-user documentation included with the redistribution, if
 20   
  *    any, must include the following acknowlegement:
 21   
  *       "This product includes software developed by the
 22   
  *        Apache Software Foundation (http://www.apache.org/)."
 23   
  *    Alternately, this acknowlegement may appear in the software itself,
 24   
  *    if and wherever such third-party acknowlegements normally appear.
 25   
  *
 26   
  * 4. The names "Ant" and "Apache Software
 27   
  *    Foundation" must not be used to endorse or promote products derived
 28   
  *    from this software without prior written permission. For written
 29   
  *    permission, please contact apache@apache.org.
 30   
  *
 31   
  * 5. Products derived from this software may not be called "Apache"
 32   
  *    nor may "Apache" appear in their names without prior written
 33   
  *    permission of the Apache Group.
 34   
  *
 35   
  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 36   
  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 37   
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 38   
  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 39   
  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 40   
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 41   
  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 42   
  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 43   
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 44   
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 45   
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 46   
  * SUCH DAMAGE.
 47   
  * ====================================================================
 48   
  *
 49   
  * This software consists of voluntary contributions made by many
 50   
  * individuals on behalf of the Apache Software Foundation.  For more
 51   
  * information on the Apache Software Foundation, please see
 52   
  * <http://www.apache.org/>.
 53   
  */
 54   
 package org.apache.tools.ant.taskdefs.optional;
 55   
 
 56   
 
 57   
 
 58   
 import java.io.File;
 59   
 import java.io.FileInputStream;
 60   
 import java.io.FileOutputStream;
 61   
 import java.io.IOException;
 62   
 import java.io.PrintStream;
 63   
 import java.util.Date;
 64   
 import java.util.Properties;
 65   
 import org.apache.tools.ant.BuildEvent;
 66   
 import org.apache.tools.ant.BuildException;
 67   
 import org.apache.tools.ant.BuildListener;
 68   
 import org.apache.tools.ant.DirectoryScanner;
 69   
 import org.apache.tools.ant.Project;
 70   
 import org.apache.tools.ant.taskdefs.Java;
 71   
 import org.apache.tools.ant.taskdefs.Javac;
 72   
 import org.apache.tools.ant.taskdefs.MatchingTask;
 73   
 import org.apache.tools.ant.taskdefs.Mkdir;
 74   
 import org.apache.tools.ant.taskdefs.compilers.DefaultCompilerAdapter;
 75   
 import org.apache.tools.ant.types.Path;
 76   
 import org.apache.tools.ant.types.Reference;
 77   
 
 78   
 /**
 79   
  * Instruments Java classes with iContract DBC preprocessor.
 80   
  * <br/>
 81   
  * The task can generate a properties file for <a href="http://hjem.sol.no/hellesoy/icontrol.html">iControl</a>,
 82   
  * a graphical user interface that lets you turn on/off assertions. iControl generates a control file that you can refer to
 83   
  * from this task using the controlfile attribute.
 84   
  * iContract is at <a href="http://www.reliable-systems.com/tools/">http://www.reliable-systems.com/tools/</a>
 85   
  * <p/>
 86   
  * Thanks to Rainer Schmitz for enhancements and comments.
 87   
  *
 88   
  * @author <a href="mailto:aslak.hellesoy@bekk.no">Aslak Helles´┐Ża>
 89   
  *
 90   
  * <p/>
 91   
  * <table border="1" cellpadding="2" cellspacing="0">
 92   
  *   <tr>
 93   
  *     <td valign="top"><b>Attribute</b></td>
 94   
  *     <td valign="top"><b>Description</b></td>
 95   
  *     <td align="center" valign="top"><b>Required</b></td>
 96   
  *   </tr>
 97   
  *   <tr>
 98   
  *     <td valign="top">srcdir</td>
 99   
  *     <td valign="top">Location of the java files.</td>
 100   
  *     <td valign="top" align="center">Yes</td>
 101   
  *   </tr>
 102   
  *   <tr>
 103   
  *     <td valign="top">instrumentdir</td>
 104   
  *     <td valign="top">Indicates where the instrumented source files should go.</td>
 105   
  *     <td valign="top" align="center">Yes</td>
 106   
  *   </tr>
 107   
  *   <tr>
 108   
  *     <td valign="top">repositorydir</td>
 109   
  *     <td valign="top">Indicates where the repository source files should go.</td>
 110   
  *     <td valign="top" align="center">Yes</td>
 111   
  *   </tr>
 112   
  *   <tr>
 113   
  *     <td valign="top">builddir</td>
 114   
  *     <td valign="top">Indicates where the compiled instrumented classes should go.
 115   
  *       Defaults to the value of instrumentdir.
 116   
  *       </p>
 117   
  *       <em>NOTE:</em> Don't use the same directory for compiled instrumented classes
 118   
  *       and uninstrumented classes. It will break the dependency checking. (Classes will
 119   
  *       not be reinstrumented if you change them).</td>
 120   
  *     <td valign="top" align="center">No</td>
 121   
  *   </tr>
 122   
  *   <tr>
 123   
  *     <td valign="top">repbuilddir</td>
 124   
  *     <td valign="top">Indicates where the compiled repository classes should go.
 125   
  *       Defaults to the value of repositorydir.</td>
 126   
  *     <td valign="top" align="center">No</td>
 127   
  *   </tr>
 128   
  *   <tr>
 129   
  *     <td valign="top">pre</td>
 130   
  *     <td valign="top">Indicates whether or not to instrument for preconditions.
 131   
  *       Defaults to <code>true</code> unless controlfile is specified, in which case it
 132   
  *       defaults to <code>false</code>.</td>
 133   
  *     <td valign="top" align="center">No</td>
 134   
  *   </tr>
 135   
  *   <tr>
 136   
  *     <td valign="top">post</td>
 137   
  *     <td valign="top">Indicates whether or not to instrument for postconditions.
 138   
  *       Defaults to <code>true</code> unless controlfile is specified, in which case it
 139   
  *       defaults to <code>false</code>.</td>
 140   
  *     <td valign="top" align="center">No</td>
 141   
  *   </tr>
 142   
  *   <tr>
 143   
  *     <td valign="top">invariant</td>
 144   
  *     <td valign="top">Indicates whether or not to instrument for invariants.
 145   
  *       Defaults to <code>true</code> unless controlfile is specified, in which case it
 146   
  *       defaults to <code>false</code>.</td>
 147   
  *     <td valign="top" align="center">No</td>
 148   
  *   </tr>
 149   
  *   <tr>
 150   
  *     <td valign="top">failthrowable</td>
 151   
  *     <td valign="top">The full name of the Throwable (Exception) that should be
 152   
  *       thrown when an assertion is violated. Defaults to <code>java.lang.Error</code></td>
 153   
  *     <td valign="top" align="center">No</td>
 154   
  *   </tr>
 155   
  *   <tr>
 156   
  *     <td valign="top">verbosity</td>
 157   
  *     <td valign="top">Indicates the verbosity level of iContract. Any combination
 158   
  *       of <code>error*,warning*,note*,info*,progress*,debug*</code> (comma separated) can be
 159   
  *       used. Defaults to <code>error*</code></td>
 160   
  *     <td valign="top" align="center">No</td>
 161   
  *   </tr>
 162   
  *   <tr>
 163   
  *     <td valign="top">quiet</td>
 164   
  *     <td valign="top">Indicates if iContract should be quiet. Turn it off if many your classes extend uninstrumented classes
 165   
  *     and you don't want warnings about this. Defaults to <code>false</code></td>
 166   
  *     <td valign="top" align="center">No</td>
 167   
  *   </tr>
 168   
  *   <tr>
 169   
  *     <td valign="top">updateicontrol</td>
 170   
  *     <td valign="top">If set to true, it indicates that the properties file for
 171   
  *       iControl in the current directory should be updated (or created if it doesn't exist).
 172   
  *       Defaults to <code>false</code>.</td>
 173   
  *     <td valign="top" align="center">No</td>
 174   
  *   </tr>
 175   
  *   <tr>
 176   
  *     <td valign="top">controlfile</td>
 177   
  *     <td valign="top">The name of the control file to pass to iContract. Consider using iControl to generate the file.
 178   
  *       Default is not to pass a file. </td>
 179   
  *     <td valign="top" align="center">Only if <code>updateicontrol=true</code></td>
 180   
  *   </tr>
 181   
  *   <tr>
 182   
  *     <td valign="top">classdir</td>
 183   
  *     <td valign="top">Indicates where compiled (unistrumented) classes are located.
 184   
  *       This is required in order to properly update the icontrol.properties file, not
 185   
  *       for instrumentation.</td>
 186   
  *     <td valign="top" align="center">Only if <code>updateicontrol=true</code></td>
 187   
  *   </tr>
 188   
  *   <tr>
 189   
  *     <td valign="top">targets</td>
 190   
  *     <td valign="top">Name of the file that will be generated by this task, which lists all the
 191   
  *        classes that iContract will instrument. If specified, the file will not be deleted after execution.
 192   
  *        If not specified, a file will still be created, but it will be deleted after execution.</td>
 193   
  *     <td valign="top" align="center">No</td>
 194   
  *   </tr>
 195   
  * </table>
 196   
  *
 197   
  * <p/>
 198   
  * <b>Note:</b> iContract will use the java compiler indicated by the project's
 199   
  * <code>build.compiler</code> property. See documentation of the Javac task for
 200   
  * more information.
 201   
  * <p/>
 202   
  * Nested includes and excludes are also supported.
 203   
  *
 204   
  * <p><b>Example:</b></p>
 205   
  * <pre>
 206   
  * &lt;icontract
 207   
  *    srcdir="${build.src}"
 208   
  *    instrumentdir="${build.instrument}"
 209   
  *    repositorydir="${build.repository}"
 210   
  *    builddir="${build.instrclasses}"
 211   
  *    updateicontrol="true"
 212   
  *    classdir="${build.classes}"
 213   
  *    controlfile="control"
 214   
  *    targets="targets"
 215   
  *    verbosity="error*,warning*"
 216   
  *    quiet="true"
 217   
  * >
 218   
  *    &lt;classpath refid="compile-classpath"/>
 219   
  * &lt;/icontract>
 220   
  * </pre>
 221   
  *
 222   
  */
 223   
 public class IContract extends MatchingTask {
 224   
 
 225   
     private static final String ICONTROL_PROPERTIES_HEADER =
 226   
         " You might want to set classRoot to point to your normal compilation class root directory.";
 227   
 
 228   
     /** compiler to use for instrumenation */
 229   
     private String icCompiler = "javac";
 230   
 
 231   
     /** temporary file with file names of all java files to be instrumented */
 232   
     private File targets = null;
 233   
 
 234   
     /**
 235   
      * will be set to true if any of the sourca files are newer than the
 236   
      * instrumented files
 237   
      */
 238   
     private boolean dirty = false;
 239   
 
 240   
     /** set to true if the iContract jar is missing */
 241   
     private boolean iContractMissing = false;
 242   
 
 243   
     /** source file root */
 244   
     private File srcDir = null;
 245   
 
 246   
     /** instrumentation src root */
 247   
     private File instrumentDir = null;
 248   
 
 249   
     /** instrumentation build root */
 250   
     private File buildDir = null;
 251   
 
 252   
     /** repository src root */
 253   
     private File repositoryDir = null;
 254   
 
 255   
     /** repository build root */
 256   
     private File repBuildDir = null;
 257   
 
 258   
     /** classpath */
 259   
     private Path classpath = null;
 260   
 
 261   
     /** The class of the Throwable to be thrown on failed assertions */
 262   
     private String failThrowable = "java.lang.Error";
 263   
 
 264   
     /** The -v option */
 265   
     private String verbosity = "error*";
 266   
 
 267   
     /** The -q option */
 268   
     private boolean quiet = false;
 269   
 
 270   
     /** The -m option */
 271   
     private File controlFile = null;
 272   
 
 273   
     /** Indicates whether or not to instrument for preconditions */
 274   
     private boolean pre = true;
 275   
     private boolean preModified = false;
 276   
 
 277   
     /** Indicates whether or not to instrument for postconditions */
 278   
     private boolean post = true;
 279   
     private boolean postModified = false;
 280   
 
 281   
     /** Indicates whether or not to instrument for invariants */
 282   
     private boolean invariant = true;
 283   
     private boolean invariantModified = false;
 284   
 
 285   
     /** Indicates whether or not to instrument all files regardless of timestamp */
 286   
     // can't be explicitly set, is set if control file exists and is newer than any source file
 287   
     private boolean instrumentall = false;
 288   
 
 289   
     /**
 290   
      * Indicates the name of a properties file (intentionally for iControl)
 291   
      * where the classpath property should be updated.
 292   
      */
 293   
     private boolean updateIcontrol = false;
 294   
 
 295   
     /** Regular compilation class root  */
 296   
     private File classDir = null;
 297   
 
 298   
     /**
 299   
      * Sets the source directory.
 300   
      *
 301   
      * @param srcDir the source directory
 302   
      */
 303  0
     public void setSrcdir(File srcDir) {
 304  0
         this.srcDir = srcDir;
 305   
     }
 306   
 
 307   
 
 308   
     /**
 309   
      * Sets the class directory (uninstrumented classes).
 310   
      *
 311   
      * @param classDir the source directory
 312   
      */
 313  0
     public void setClassdir(File classDir) {
 314  0
         this.classDir = classDir;
 315   
     }
 316   
 
 317   
 
 318   
     /**
 319   
      * Sets the instrumentation directory.
 320   
      *
 321   
      * @param instrumentDir the source directory
 322   
      */
 323  0
     public void setInstrumentdir(File instrumentDir) {
 324  0
         this.instrumentDir = instrumentDir;
 325  0
         if (this.buildDir == null) {
 326  0
             setBuilddir(instrumentDir);
 327   
         }
 328   
     }
 329   
 
 330   
 
 331   
     /**
 332   
      * Sets the build directory for instrumented classes.
 333   
      *
 334   
      * @param buildDir the build directory
 335   
      */
 336  0
     public void setBuilddir(File buildDir) {
 337  0
         this.buildDir = buildDir;
 338   
     }
 339   
 
 340   
 
 341   
     /**
 342   
      * Sets the build directory for repository classes.
 343   
      *
 344   
      * @param repositoryDir the source directory
 345   
      */
 346  0
     public void setRepositorydir(File repositoryDir) {
 347  0
         this.repositoryDir = repositoryDir;
 348  0
         if (this.repBuildDir == null) {
 349  0
             setRepbuilddir(repositoryDir);
 350   
         }
 351   
     }
 352   
 
 353   
 
 354   
     /**
 355   
      * Sets the build directory for instrumented classes.
 356   
      *
 357   
      * @param repBuildDir the build directory
 358   
      */
 359  0
     public void setRepbuilddir(File repBuildDir) {
 360  0
         this.repBuildDir = repBuildDir;
 361   
     }
 362   
 
 363   
 
 364   
     /**
 365   
      * Turns on/off precondition instrumentation.
 366   
      *
 367   
      * @param pre true turns it on
 368   
      */
 369  0
     public void setPre(boolean pre) {
 370  0
         this.pre = pre;
 371  0
         preModified = true;
 372   
     }
 373   
 
 374   
 
 375   
     /**
 376   
      * Turns on/off postcondition instrumentation.
 377   
      *
 378   
      * @param post true turns it on
 379   
      */
 380  0
     public void setPost(boolean post) {
 381  0
         this.post = post;
 382  0
         postModified = true;
 383   
     }
 384   
 
 385   
 
 386   
     /**
 387   
      * Turns on/off invariant instrumentation.
 388   
      *
 389   
      * @param invariant true turns it on
 390   
      */
 391  0
     public void setInvariant(boolean invariant) {
 392  0
         this.invariant = invariant;
 393  0
         invariantModified = true;
 394   
     }
 395   
 
 396   
 
 397   
     /**
 398   
      * Sets the Throwable (Exception) to be thrown on assertion violation.
 399   
      *
 400   
      * @param clazz the fully qualified Throwable class name
 401   
      */
 402  0
     public void setFailthrowable(String clazz) {
 403  0
         this.failThrowable = clazz;
 404   
     }
 405   
 
 406   
 
 407   
     /**
 408   
      * Sets the verbosity level of iContract. Any combination of
 409   
      * error*,warning*,note*,info*,progress*,debug* (comma separated) can be
 410   
      * used. Defaults to error*,warning*
 411   
      *
 412   
      * @param verbosity verbosity level
 413   
      */
 414  0
     public void setVerbosity(String verbosity) {
 415  0
         this.verbosity = verbosity;
 416   
     }
 417   
 
 418   
 
 419   
     /**
 420   
      * Tells iContract to be quiet.
 421   
      *
 422   
      * @param quiet true if iContract should be quiet.
 423   
      */
 424  0
     public void setQuiet(boolean quiet) {
 425  0
         this.quiet = quiet;
 426   
     }
 427   
 
 428   
 
 429   
     /**
 430   
      * Sets the name of the file where targets will be written. That is the
 431   
      * file that tells iContract what files to process.
 432   
      *
 433   
      * @param targets the targets file name
 434   
      */
 435  0
     public void setTargets(File targets) {
 436  0
         this.targets = targets;
 437   
     }
 438   
 
 439   
 
 440   
     /**
 441   
      * Sets the control file to pass to iContract.
 442   
      *
 443   
      * @param controlFile the control file
 444   
      */
 445  0
     public void setControlfile(File controlFile) {
 446  0
         if (!controlFile.exists()) {
 447  0
             log("WARNING: Control file " + controlFile.getAbsolutePath()
 448   
                  + " doesn't exist. iContract will be run "
 449   
                  + "without control file.");
 450   
         }
 451  0
         this.controlFile = controlFile;
 452   
     }
 453   
 
 454   
 
 455   
     /**
 456   
      * Sets the classpath to be used for invocation of iContract.
 457   
      *
 458   
      * @param path the classpath
 459   
      */
 460  0
     public void setClasspath(Path path) {
 461  0
         createClasspath().append(path);
 462   
     }
 463   
 
 464   
 
 465   
     /**
 466   
      * Sets the classpath.
 467   
      *
 468   
      * @return the nested classpath element
 469   
      * @todo this overwrites the classpath so only one
 470   
      *       effective classpath element would work. This
 471   
      *       is not how we do this elsewhere.
 472   
      */
 473  0
     public Path createClasspath() {
 474  0
         if (classpath == null) {
 475  0
             classpath = new Path(getProject());
 476   
         }
 477  0
         return classpath;
 478   
     }
 479   
 
 480   
 
 481   
     /**
 482   
      * Adds a reference to a classpath defined elsewhere.
 483   
      *
 484   
      * @param reference referenced classpath
 485   
      */
 486  0
     public void setClasspathRef(Reference reference) {
 487  0
         createClasspath().setRefid(reference);
 488   
     }
 489   
 
 490   
 
 491   
     /**
 492   
      * If true, updates iControl properties file
 493   
      *
 494   
      * @param updateIcontrol true if iControl properties file should be
 495   
      *      updated
 496   
      */
 497  0
     public void setUpdateicontrol(boolean updateIcontrol) {
 498  0
         this.updateIcontrol = updateIcontrol;
 499   
     }
 500   
 
 501   
 
 502   
     /**
 503   
      * Executes the task
 504   
      *
 505   
      * @exception BuildException if the instrumentation fails
 506   
      */
 507  0
     public void execute() throws BuildException {
 508  0
         preconditions();
 509  0
         scan();
 510  0
         if (dirty) {
 511   
 
 512   
             // turn off assertions if we're using controlfile, unless they are not explicitly set.
 513  0
             boolean useControlFile = (controlFile != null) && controlFile.exists();
 514   
 
 515  0
             if (useControlFile && !preModified) {
 516  0
                 pre = false;
 517   
             }
 518  0
             if (useControlFile && !postModified) {
 519  0
                 post = false;
 520   
             }
 521  0
             if (useControlFile && !invariantModified) {
 522  0
                 invariant = false;
 523   
             }
 524   
             // issue warning if pre,post or invariant is used together with controlfile
 525  0
             if ((pre || post || invariant) && controlFile != null) {
 526  0
                 log("WARNING: specifying pre,post or invariant will "
 527   
                      + "override control file settings");
 528   
             }
 529   
 
 530   
 
 531   
             // We want to be notified if iContract jar is missing. This makes life easier for the user
 532   
             // who didn't understand that iContract is a separate library (duh!)
 533  0
             getProject().addBuildListener(new IContractPresenceDetector());
 534   
 
 535   
             // Prepare the directories for iContract. iContract will make them if they
 536   
             // don't exist, but for some reason I don't know, it will complain about the REP files
 537   
             // afterwards
 538  0
             Mkdir mkdir = (Mkdir) getProject().createTask("mkdir");
 539   
 
 540  0
             mkdir.setDir(instrumentDir);
 541  0
             mkdir.execute();
 542  0
             mkdir.setDir(buildDir);
 543  0
             mkdir.execute();
 544  0
             mkdir.setDir(repositoryDir);
 545  0
             mkdir.execute();
 546   
 
 547   
             // Set the classpath that is needed for regular Javac compilation
 548  0
             Path baseClasspath = createClasspath();
 549   
 
 550   
             // Might need to add the core classes if we're not using Sun's Javac (like Jikes)
 551  0
             String compiler = getProject().getProperty("build.compiler");
 552  0
             ClasspathHelper classpathHelper = new ClasspathHelper(compiler);
 553   
 
 554  0
             classpathHelper.modify(baseClasspath);
 555   
 
 556   
             // Create the classpath required to compile the sourcefiles BEFORE instrumentation
 557  0
             Path beforeInstrumentationClasspath = ((Path) baseClasspath.clone());
 558   
 
 559  0
             beforeInstrumentationClasspath.append(new Path(getProject(),
 560   
                 srcDir.getAbsolutePath()));
 561   
 
 562   
             // Create the classpath required to compile the sourcefiles AFTER instrumentation
 563  0
             Path afterInstrumentationClasspath = ((Path) baseClasspath.clone());
 564   
 
 565  0
             afterInstrumentationClasspath.append(new Path(getProject(), instrumentDir.getAbsolutePath()));
 566  0
             afterInstrumentationClasspath.append(new Path(getProject(), repositoryDir.getAbsolutePath()));
 567  0
             afterInstrumentationClasspath.append(new Path(getProject(), srcDir.getAbsolutePath()));
 568  0
             afterInstrumentationClasspath.append(new Path(getProject(), buildDir.getAbsolutePath()));
 569   
 
 570   
             // Create the classpath required to automatically compile the repository files
 571  0
             Path repositoryClasspath = ((Path) baseClasspath.clone());
 572   
 
 573  0
             repositoryClasspath.append(new Path(getProject(), instrumentDir.getAbsolutePath()));
 574  0
             repositoryClasspath.append(new Path(getProject(), srcDir.getAbsolutePath()));
 575  0
             repositoryClasspath.append(new Path(getProject(), repositoryDir.getAbsolutePath()));
 576  0
             repositoryClasspath.append(new Path(getProject(), buildDir.getAbsolutePath()));
 577   
 
 578   
             // Create the classpath required for iContract itself
 579  0
             Path iContractClasspath = ((Path) baseClasspath.clone());
 580   
 
 581  0
             iContractClasspath.append(new Path(getProject(), System.getProperty("java.home") + File.separator + ".." + File.separator + "lib" + File.separator + "tools.jar"));
 582  0
             iContractClasspath.append(new Path(getProject(), srcDir.getAbsolutePath()));
 583  0
             iContractClasspath.append(new Path(getProject(), repositoryDir.getAbsolutePath()));
 584  0
             iContractClasspath.append(new Path(getProject(), instrumentDir.getAbsolutePath()));
 585  0
             iContractClasspath.append(new Path(getProject(), buildDir.getAbsolutePath()));
 586   
 
 587   
             // Create a forked java process
 588  0
             Java iContract = (Java) getProject().createTask("java");
 589   
 
 590  0
             iContract.setTaskName(getTaskName());
 591  0
             iContract.setFork(true);
 592  0
             iContract.setClassname("com.reliablesystems.iContract.Tool");
 593  0
             iContract.setClasspath(iContractClasspath);
 594   
 
 595   
             // Build the arguments to iContract
 596  0
             StringBuffer args = new StringBuffer();
 597   
 
 598  0
             args.append(directiveString());
 599  0
             args.append("-v").append(verbosity).append(" ");
 600  0
             args.append("-b").append("\"").append(icCompiler).append(" -classpath ").append(beforeInstrumentationClasspath).append("\" ");
 601  0
             args.append("-c").append("\"").append(icCompiler).append(" -classpath ").append(afterInstrumentationClasspath).append(" -d ").append(buildDir).append("\" ");
 602  0
             args.append("-n").append("\"").append(icCompiler).append(" -classpath ").append(repositoryClasspath).append("\" ");
 603  0
             args.append("-d").append(failThrowable).append(" ");
 604  0
             args.append("-o").append(instrumentDir).append(File.separator).append("@p").append(File.separator).append("@f.@e ");
 605  0
             args.append("-k").append(repositoryDir).append(File.separator).append("@p ");
 606  0
             args.append(quiet ? "-q " : "");
 607  0
             args.append(instrumentall ? "-a " : "");// reinstrument everything if controlFile exists and is newer than any class
 608  0
             args.append("@").append(targets.getAbsolutePath());
 609  0
             iContract.createArg().setLine(args.toString());
 610   
 
 611   
 //System.out.println( "JAVA -classpath " + iContractClasspath + " com.reliablesystems.iContract.Tool " + args.toString() );
 612   
 
 613   
             // update iControlProperties if it's set.
 614  0
             if (updateIcontrol) {
 615  0
                 Properties iControlProps = new Properties();
 616   
 
 617  0
                 try {// to read existing propertiesfile
 618  0
                     iControlProps.load(new FileInputStream("icontrol.properties"));
 619   
                 } catch (IOException e) {
 620  0
                     log("File icontrol.properties not found. That's ok. Writing a default one.");
 621   
                 }
 622  0
                 iControlProps.setProperty("sourceRoot", srcDir.getAbsolutePath());
 623  0
                 iControlProps.setProperty("classRoot", classDir.getAbsolutePath());
 624  0
                 iControlProps.setProperty("classpath", afterInstrumentationClasspath.toString());
 625  0
                 iControlProps.setProperty("controlFile", controlFile.getAbsolutePath());
 626  0
                 iControlProps.setProperty("targetsFile", targets.getAbsolutePath());
 627   
 
 628  0
                 try {// to read existing propertiesfile
 629  0
                     iControlProps.store(new FileOutputStream("icontrol.properties"), ICONTROL_PROPERTIES_HEADER);
 630  0
                     log("Updated icontrol.properties");
 631   
                 } catch (IOException e) {
 632  0
                     log("Couldn't write icontrol.properties.");
 633   
                 }
 634   
             }
 635   
 
 636   
             // do it!
 637  0
             int result = iContract.executeJava();
 638   
 
 639  0
             if (result != 0) {
 640  0
                 if (iContractMissing) {
 641  0
                     log("iContract can't be found on your classpath. Your classpath is:");
 642  0
                     log(classpath.toString());
 643  0
                     log("If you don't have the iContract jar, go get it at http://www.reliable-systems.com/tools/");
 644   
                 }
 645  0
                 throw new BuildException("iContract instrumentation failed. Code=" + result);
 646   
             }
 647   
         } else {// not dirty
 648   
             //log( "Nothing to do. Everything up to date." );
 649   
         }
 650   
     }
 651   
 
 652   
 
 653   
     /** Checks that the required attributes are set.  */
 654  0
     private void preconditions() throws BuildException {
 655  0
         if (srcDir == null) {
 656  0
             throw new BuildException("srcdir attribute must be set!", getLocation());
 657   
         }
 658  0
         if (!srcDir.exists()) {
 659  0
             throw new BuildException("srcdir \"" + srcDir.getPath() + "\" does not exist!", getLocation());
 660   
         }
 661  0
         if (instrumentDir == null) {
 662  0
             throw new BuildException("instrumentdir attribute must be set!", getLocation());
 663   
         }
 664  0
         if (repositoryDir == null) {
 665  0
             throw new BuildException("repositorydir attribute must be set!", getLocation());
 666   
         }
 667  0
         if (updateIcontrol == true && classDir == null) {
 668  0
             throw new BuildException("classdir attribute must be specified when updateicontrol=true!", getLocation());
 669   
         }
 670  0
         if (updateIcontrol == true && controlFile == null) {
 671  0
             throw new BuildException("controlfile attribute must be specified when updateicontrol=true!", getLocation());
 672   
         }
 673   
     }
 674   
 
 675   
 
 676   
     /**
 677   
      * Verifies whether any of the source files have changed. Done by
 678   
      * comparing date of source/class files. The whole lot is "dirty" if at
 679   
      * least one source file or the control file is newer than the
 680   
      * instrumented files. If not dirty, iContract will not be executed. <br/>
 681   
      * Also creates a temporary file with a list of the source files, that
 682   
      * will be deleted upon exit.
 683   
      */
 684  0
     private void scan() throws BuildException {
 685  0
         long now = (new Date()).getTime();
 686   
 
 687  0
         DirectoryScanner ds = null;
 688   
 
 689  0
         ds = getDirectoryScanner(srcDir);
 690   
 
 691  0
         String[] files = ds.getIncludedFiles();
 692   
 
 693  0
         FileOutputStream targetOutputStream = null;
 694  0
         PrintStream targetPrinter = null;
 695  0
         boolean writeTargets = false;
 696   
 
 697  0
         try {
 698  0
             if (targets == null) {
 699  0
                 targets = new File("targets");
 700  0
                 log("Warning: targets file not specified. generating file: " + targets.getName());
 701  0
                 writeTargets = true;
 702  0
             } else if (!targets.exists()) {
 703  0
                 log("Specified targets file doesn't exist. generating file: " + targets.getName());
 704  0
                 writeTargets = true;
 705   
             }
 706  0
             if (writeTargets) {
 707  0
                 log("You should consider using iControl to create a target file.");
 708  0
                 targetOutputStream = new FileOutputStream(targets);
 709  0
                 targetPrinter = new PrintStream(targetOutputStream);
 710   
             }
 711  0
             for (int i = 0; i < files.length; i++) {
 712  0
                 File srcFile = new File(srcDir, files[i]);
 713   
 
 714  0
                 if (files[i].endsWith(".java")) {
 715   
                     // print the target, while we're at here. (Only if generatetarget=true).
 716  0
                     if (targetPrinter != null) {
 717  0
                         targetPrinter.println(srcFile.getAbsolutePath());
 718   
                     }
 719  0
                     File classFile = new File(buildDir, files[i].substring(0, files[i].indexOf(".java")) + ".class");
 720   
 
 721  0
                     if (srcFile.lastModified() > now) {
 722  0
                         log("Warning: file modified in the future: " +
 723   
                             files[i], Project.MSG_WARN);
 724   
                     }
 725   
 
 726  0
                     if (!classFile.exists() || srcFile.lastModified() > classFile.lastModified()) {
 727   
                         //log( "Found a file newer than the instrumentDir class file: " + srcFile.getPath() + " newer than " + classFile.getPath() + ". Running iContract again..." );
 728  0
                         dirty = true;
 729   
                     }
 730   
                 }
 731   
             }
 732  0
             if (targetPrinter != null) {
 733  0
                 targetPrinter.flush();
 734  0
                 targetPrinter.close();
 735   
             }
 736   
         } catch (IOException e) {
 737  0
             throw new BuildException("Could not create target file:" + e.getMessage());
 738   
         }
 739   
 
 740   
         // also, check controlFile timestamp
 741  0
         long controlFileTime = -1;
 742   
 
 743  0
         try {
 744  0
             if (controlFile != null) {
 745  0
                 if (controlFile.exists() && buildDir.exists()) {
 746  0
                     controlFileTime = controlFile.lastModified();
 747  0
                     ds = getDirectoryScanner(buildDir);
 748  0
                     files = ds.getIncludedFiles();
 749  0
                     for (int i = 0; i < files.length; i++) {
 750  0
                         File srcFile = new File(srcDir, files[i]);
 751   
 
 752  0
                         if (files[i].endsWith(".class")) {
 753  0
                             if (controlFileTime > srcFile.lastModified()) {
 754  0
                                 if (!dirty) {
 755  0
                                     log("Control file " + controlFile.getAbsolutePath() + " has been updated. Instrumenting all files...");
 756   
                                 }
 757  0
                                 dirty = true;
 758  0
                                 instrumentall = true;
 759   
                             }
 760   
                         }
 761   
                     }
 762   
                 }
 763   
             }
 764   
         } catch (Throwable t) {
 765  0
             throw new BuildException("Got an interesting exception:" + t.getMessage());
 766   
         }
 767   
     }
 768   
 
 769   
 
 770   
     /**
 771   
      * Creates the -m option based on the values of controlFile, pre, post and
 772   
      * invariant.
 773   
      */
 774  0
     private final String directiveString() {
 775  0
         StringBuffer sb = new StringBuffer();
 776  0
         boolean comma = false;
 777   
 
 778  0
         boolean useControlFile = (controlFile != null) && controlFile.exists();
 779   
 
 780  0
         if (useControlFile || pre || post || invariant) {
 781  0
             sb.append("-m");
 782   
         }
 783  0
         if (useControlFile) {
 784  0
             sb.append("@").append(controlFile);
 785  0
             comma = true;
 786   
         }
 787  0
         if (pre) {
 788  0
             if (comma) {
 789  0
                 sb.append(",");
 790   
             }
 791  0
             sb.append("pre");
 792  0
             comma = true;
 793   
         }
 794  0
         if (post) {
 795  0
             if (comma) {
 796  0
                 sb.append(",");
 797   
             }
 798  0
             sb.append("post");
 799  0
             comma = true;
 800   
         }
 801  0
         if (invariant) {
 802  0
             if (comma) {
 803  0
                 sb.append(",");
 804   
             }
 805  0
             sb.append("inv");
 806   
         }
 807  0
         sb.append(" ");
 808  0
         return sb.toString();
 809   
     }
 810   
 
 811   
 
 812   
     /**
 813   
      * BuildListener that sets the iContractMissing flag to true if a message
 814   
      * about missing iContract is missing. Used to indicate a more verbose
 815   
      * error to the user, with advice about how to solve the problem
 816   
      *
 817   
      * @author Conor MacNeill
 818   
      */
 819   
     private class IContractPresenceDetector implements BuildListener {
 820  0
         public void buildFinished(BuildEvent event) {
 821   
         }
 822   
 
 823   
 
 824  0
         public void buildStarted(BuildEvent event) {
 825   
         }
 826   
 
 827   
 
 828  0
         public void messageLogged(BuildEvent event) {
 829  0
             if ("java.lang.NoClassDefFoundError: com/reliablesystems/iContract/Tool".equals(event.getMessage())) {
 830  0
                 iContractMissing = true;
 831   
             }
 832   
         }
 833   
 
 834   
 
 835  0
         public void targetFinished(BuildEvent event) {
 836   
         }
 837   
 
 838   
 
 839  0
         public void targetStarted(BuildEvent event) {
 840   
         }
 841   
 
 842   
 
 843  0
         public void taskFinished(BuildEvent event) {
 844   
         }
 845   
 
 846   
 
 847  0
         public void taskStarted(BuildEvent event) {
 848   
         }
 849   
     }
 850   
 
 851   
 
 852   
     /**
 853   
      * This class is a helper to set correct classpath for other compilers,
 854   
      * like Jikes. It reuses the logic from DefaultCompilerAdapter, which is
 855   
      * protected, so we have to subclass it.
 856   
      *
 857   
      * @author Conor MacNeill
 858   
      */
 859   
     private class ClasspathHelper extends DefaultCompilerAdapter {
 860   
         private final String compiler;
 861   
 
 862   
 
 863  0
         public ClasspathHelper(String compiler) {
 864  0
             super();
 865  0
             this.compiler = compiler;
 866   
         }
 867   
 
 868   
         // make it public
 869  0
         public void modify(Path path) {
 870   
             // depending on what compiler to use, set the includeJavaRuntime flag
 871  0
             if ("jikes".equals(compiler)) {
 872  0
                 icCompiler = compiler;
 873  0
                 includeJavaRuntime = true;
 874  0
                 path.append(getCompileClasspath());
 875   
             }
 876   
         }
 877   
 
 878   
         // dummy implementation. Never called
 879  0
         public void setJavac(Javac javac) {
 880   
         }
 881   
 
 882   
 
 883  0
         public boolean execute() {
 884  0
             return true;
 885   
         }
 886   
     }
 887   
 }
 888   
 
 889