Clover coverage report - Ant Coverage
Coverage timestamp: Tue Apr 8 2003 20:43:55 EST
file stats: LOC: 577   Methods: 27
NCLOC: 309   Classes: 2
 
 Source file Conditionals Statements Methods TOTAL
JDependTask.java 1.5% 4.2% 0% 3%
 1   
 /*
 2   
  * The Apache Software License, Version 1.1
 3   
  *
 4   
  * Copyright (c) 2001-2003 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   
 
 55   
 package org.apache.tools.ant.taskdefs.optional.jdepend;
 56   
 
 57   
 import java.io.File;
 58   
 import java.io.FileWriter;
 59   
 import java.io.IOException;
 60   
 import java.io.PrintWriter;
 61   
 import java.lang.reflect.Constructor;
 62   
 import java.lang.reflect.Method;
 63   
 import java.util.Vector;
 64   
 import org.apache.tools.ant.BuildException;
 65   
 import org.apache.tools.ant.PathTokenizer;
 66   
 import org.apache.tools.ant.Project;
 67   
 import org.apache.tools.ant.Task;
 68   
 import org.apache.tools.ant.taskdefs.Execute;
 69   
 import org.apache.tools.ant.taskdefs.ExecuteWatchdog;
 70   
 import org.apache.tools.ant.taskdefs.LogStreamHandler;
 71   
 import org.apache.tools.ant.types.Commandline;
 72   
 import org.apache.tools.ant.types.CommandlineJava;
 73   
 import org.apache.tools.ant.types.EnumeratedAttribute;
 74   
 import org.apache.tools.ant.types.Path;
 75   
 import org.apache.tools.ant.types.PatternSet;
 76   
 import org.apache.tools.ant.types.Reference;
 77   
 
 78   
 /**
 79   
  * Runs JDepend tests.
 80   
  *
 81   
  * <p>JDepend is a tool to generate design quality metrics for each Java package.
 82   
  * It has been initially created by Mike Clark. JDepend can be found at <a
 83   
  * href="http://www.clarkware.com/software/JDepend.html">http://www.clarkware.com/software/JDepend.html</a>.
 84   
  *
 85   
  * The current implementation spawn a new Java VM.
 86   
  *
 87   
  * @author <a href="mailto:Jerome@jeromelacoste.com">Jerome Lacoste</a>
 88   
  * @author <a href="mailto:roxspring@yahoo.com">Rob Oxspring</a>
 89   
  */
 90   
 public class JDependTask extends Task {
 91   
     //private CommandlineJava commandline = new CommandlineJava();
 92   
 
 93   
     // required attributes
 94   
     private Path _sourcesPath; // Deprecated!
 95   
     private Path _classesPath; // Use this going forward
 96   
 
 97   
     // optional attributes
 98   
     private File _outputFile;
 99   
     private File _dir;
 100   
     private Path _compileClasspath;
 101   
     private boolean _haltonerror = false;
 102   
     private boolean _fork = false;
 103   
     //private Integer _timeout = null;
 104   
 
 105   
     private String _jvm = null;
 106   
     private String format = "text";
 107   
     private PatternSet defaultPatterns = new PatternSet();
 108   
 
 109   
     private static Constructor packageFilterC;
 110   
     private static Method setFilter;
 111   
 
 112   
     static {
 113  1
         try {
 114  1
             Class packageFilter = 
 115   
                 Class.forName("jdepend.framework.PackageFilter");
 116  1
             packageFilterC = 
 117   
                 packageFilter.getConstructor(new Class[] {java.util.Collection.class});
 118  1
             setFilter = 
 119   
                 jdepend.textui.JDepend.class.getDeclaredMethod("setFilter",
 120   
                                                                new Class[] {packageFilter});
 121   
         } catch (Throwable t) {
 122  1
             if (setFilter == null) {
 123  1
                 packageFilterC = null;
 124   
             }
 125   
         }
 126   
     }
 127   
 
 128  0
     public JDependTask() {
 129   
     }
 130   
 
 131   
     /*
 132   
       public void setTimeout(Integer value) {
 133   
       _timeout = value;
 134   
       }
 135   
 
 136   
       public Integer getTimeout() {
 137   
       return _timeout;
 138   
       }
 139   
     */
 140   
 
 141   
     /**
 142   
      * The output file name.
 143   
      *
 144   
      * @param outputFile
 145   
      */
 146  0
     public void setOutputFile(File outputFile) {
 147  0
         _outputFile = outputFile;
 148   
     }
 149   
 
 150  0
     public File getOutputFile() {
 151  0
         return _outputFile;
 152   
     }
 153   
 
 154   
     /**
 155   
      * Whether or not to halt on failure. Default: false.
 156   
      */
 157  0
     public void setHaltonerror(boolean value) {
 158  0
         _haltonerror = value;
 159   
     }
 160   
 
 161  0
     public boolean getHaltonerror() {
 162  0
         return _haltonerror;
 163   
     }
 164   
 
 165   
     /**
 166   
      * If true, forks into a new JVM. Default: false.
 167   
      *
 168   
      * @param   value   <tt>true</tt> if a JVM should be forked, otherwise <tt>false<tt>
 169   
      */
 170  0
     public void setFork(boolean value) {
 171  0
         _fork = value;
 172   
     }
 173   
 
 174  0
     public boolean getFork() {
 175  0
         return _fork;
 176   
     }
 177   
 
 178   
     /**
 179   
      * The command used to invoke a forked Java Virtual Machine.
 180   
      *
 181   
      * Default is <tt>java</tt>. Ignored if no JVM is forked.
 182   
      * @param   value   the new VM to use instead of <tt>java</tt>
 183   
      * @see #setFork(boolean)
 184   
      */
 185  0
     public void setJvm(String value) {
 186  0
         _jvm = value;
 187   
 
 188   
     }
 189   
 
 190   
     /**
 191   
      * Adds a path to source code to analyze.
 192   
      * @deprecated
 193   
      */
 194  0
     public Path createSourcespath() {
 195  0
         if (_sourcesPath == null) {
 196  0
             _sourcesPath = new Path(getProject());
 197   
         }
 198  0
         return _sourcesPath.createPath();
 199   
     }
 200   
 
 201   
     /**
 202   
      * Gets the sourcepath.
 203   
      * 
 204   
      * @deprecated
 205   
      * 
 206   
      */
 207  0
     public Path getSourcespath() {
 208  0
         return _sourcesPath;
 209   
     }
 210   
 
 211   
     /**
 212   
      * Adds a path to class code to analyze.
 213   
      */
 214  0
     public Path createClassespath() {
 215  0
         if (_classesPath == null) {
 216  0
             _classesPath = new Path(getProject());
 217   
         }
 218  0
         return _classesPath.createPath();
 219   
     }
 220   
 
 221   
     /**
 222   
      * Gets the classespath.
 223   
      * 
 224   
      */
 225  0
     public Path getClassespath() {
 226  0
         return _classesPath;
 227   
     }
 228   
 
 229   
     /**
 230   
      * The directory to invoke the VM in. Ignored if no JVM is forked.
 231   
      * @param   dir     the directory to invoke the JVM from.
 232   
      * @see #setFork(boolean)
 233   
      */
 234  0
     public void setDir(File dir) {
 235  0
         _dir = dir;
 236   
     }
 237   
 
 238  0
     public File getDir() {
 239  0
         return _dir;
 240   
     }
 241   
 
 242   
     /**
 243   
      * Set the classpath to be used for this compilation.
 244   
      */
 245  0
     public void setClasspath(Path classpath) {
 246  0
         if (_compileClasspath == null) {
 247  0
             _compileClasspath = classpath;
 248   
         } else {
 249  0
             _compileClasspath.append(classpath);
 250   
         }
 251   
     }
 252   
 
 253   
     /** Gets the classpath to be used for this compilation. */
 254  0
     public Path getClasspath() {
 255  0
         return _compileClasspath;
 256   
     }
 257   
 
 258   
     /**
 259   
      * Adds a path to the classpath.
 260   
      */
 261  0
     public Path createClasspath() {
 262  0
         if (_compileClasspath == null) {
 263  0
             _compileClasspath = new Path(getProject());
 264   
         }
 265  0
         return _compileClasspath.createPath();
 266   
     }
 267   
 
 268   
     /**
 269   
      * Create a new JVM argument. Ignored if no JVM is forked.
 270   
      * @return  create a new JVM argument so that any argument can be passed to the JVM.
 271   
      * @see #setFork(boolean)
 272   
      */
 273  0
     public Commandline.Argument createJvmarg(CommandlineJava commandline) {
 274  0
         return commandline.createVmArgument();
 275   
     }
 276   
 
 277   
     /**
 278   
      * Adds a reference to a classpath defined elsewhere.
 279   
      */
 280  0
     public void setClasspathRef(Reference r) {
 281  0
         createClasspath().setRefid(r);
 282   
     }
 283   
 
 284   
     /**
 285   
      * add a name entry on the exclude list
 286   
      */
 287  0
     public PatternSet.NameEntry createExclude() {
 288  0
         return defaultPatterns.createExclude();
 289   
     }
 290   
 
 291  0
     public PatternSet getExcludes() {
 292  0
         return defaultPatterns;
 293   
     }
 294   
 
 295   
     /**
 296   
      * The format to write the output in, "xml" or "text".
 297   
      *
 298   
      * @param ea
 299   
      */
 300  0
     public void setFormat(FormatAttribute ea) {
 301  0
         format = ea.getValue();
 302   
     }
 303   
 
 304   
     public static class FormatAttribute extends EnumeratedAttribute {
 305   
         private String [] formats = new String[]{"xml", "text"};
 306   
 
 307  0
         public String[] getValues() {
 308  0
             return formats;
 309   
         }
 310   
     }
 311   
 
 312   
     /**
 313   
      * No problems with this test.
 314   
      */
 315   
     private static final int SUCCESS = 0;
 316   
     /**
 317   
      * An error occured.
 318   
      */
 319   
     private static final int ERRORS = 1;
 320   
 
 321  0
     public void execute() throws BuildException {
 322   
 
 323  0
         CommandlineJava commandline = new CommandlineJava();
 324   
 
 325  0
         if ("text".equals(format)) {
 326  0
             commandline.setClassname("jdepend.textui.JDepend");
 327   
         } else
 328  0
             if ("xml".equals(format)) {
 329  0
                 commandline.setClassname("jdepend.xmlui.JDepend");
 330   
             }
 331   
 
 332  0
         if (_jvm != null) {
 333  0
             commandline.setVm(_jvm);
 334   
         }
 335  0
         if (getSourcespath() == null && getClassespath() == null) {
 336  0
             throw new BuildException("Missing classespath required argument");
 337  0
         } else if (getClassespath() == null) {
 338  0
             String msg =
 339   
                 "sourcespath is deprecated in JDepend >= 2.5 "
 340   
                 + "- please convert to classespath";
 341  0
             log(msg);
 342   
         }
 343   
 
 344   
         // execute the test and get the return code
 345  0
         int exitValue = JDependTask.ERRORS;
 346   
         //boolean wasKilled = false;
 347  0
         if (!getFork()) {
 348  0
             exitValue = executeInVM(commandline);
 349   
         } else {
 350  0
             ExecuteWatchdog watchdog = createWatchdog();
 351  0
             exitValue = executeAsForked(commandline, watchdog);
 352   
             // null watchdog means no timeout, you'd better not check with null
 353  0
             if (watchdog != null) {
 354   
                 //info will be used in later version do nothing for now
 355   
                 //wasKilled = watchdog.killedProcess();
 356   
             }
 357   
         }
 358   
 
 359   
         // if there is an error/failure and that it should halt, stop 
 360   
         // everything otherwise just log a statement
 361  0
         boolean errorOccurred = exitValue == JDependTask.ERRORS;
 362   
 
 363  0
         if (errorOccurred) {
 364  0
             if  (getHaltonerror()) {
 365  0
                 throw new BuildException("JDepend failed",
 366   
                                          getLocation());
 367   
             } else {
 368  0
                 log("JDepend FAILED", Project.MSG_ERR);
 369   
             }
 370   
         }
 371   
     }
 372   
 
 373   
     // this comment extract from JUnit Task may also apply here
 374   
     // "in VM is not very nice since it could probably hang the
 375   
     // whole build. IMHO this method should be avoided and it would be best
 376   
     // to remove it in future versions. TBD. (SBa)"
 377   
 
 378   
     /**
 379   
      * Execute inside VM.
 380   
      */
 381  0
     public int executeInVM(CommandlineJava commandline) throws BuildException {
 382  0
         jdepend.textui.JDepend jdepend;
 383   
 
 384  0
         if ("xml".equals(format)) {
 385  0
             jdepend = new jdepend.xmlui.JDepend();
 386   
         } else {
 387  0
             jdepend = new jdepend.textui.JDepend();
 388   
         }
 389   
 
 390  0
         if (getOutputFile() != null) {
 391  0
             FileWriter fw;
 392  0
             try {
 393  0
                 fw = new FileWriter(getOutputFile().getPath());
 394   
             } catch (IOException e) {
 395  0
                 String msg = "JDepend Failed when creating the output file: " 
 396   
                     + e.getMessage();
 397  0
                 log(msg);
 398  0
                 throw new BuildException(msg);
 399   
             }
 400  0
             jdepend.setWriter(new PrintWriter(fw));
 401  0
             log("Output to be stored in " + getOutputFile().getPath());
 402   
         }
 403   
 
 404  0
         if (getClassespath() != null) {
 405   
             // This is the new, better way - use classespath instead
 406   
             // of sourcespath.  The code is currently the same - you
 407   
             // need class files in a directory to use this - jar files
 408   
             // coming soon....
 409  0
             String[] classesPath = getClassespath().list();
 410  0
             for (int i = 0; i < classesPath.length; i++) {
 411  0
                 File f = new File(classesPath[i]);
 412   
                 // not necessary as JDepend would fail, but why loose
 413   
                 // some time?
 414  0
                 if (!f.exists() || !f.isDirectory()) {
 415  0
                     String msg = "\""
 416   
                         + f.getPath()
 417   
                         + "\" does not represent a valid"
 418   
                         + " directory. JDepend would fail.";
 419  0
                     log(msg);
 420  0
                     throw new BuildException(msg);
 421   
                 }
 422  0
                 try {
 423  0
                     jdepend.addDirectory(f.getPath());
 424   
                 } catch (IOException e) {
 425  0
                     String msg =
 426   
                         "JDepend Failed when adding a class directory: "
 427   
                         + e.getMessage();
 428  0
                     log(msg);
 429  0
                     throw new BuildException(msg);
 430   
                 }
 431   
             }
 432   
 
 433  0
         } else if (getSourcespath() != null) {
 434   
 
 435   
             // This is the old way and is deprecated - classespath is
 436   
             // the right way to do this and is above
 437  0
             String[] sourcesPath = getSourcespath().list();
 438  0
             for (int i = 0; i < sourcesPath.length; i++) {
 439  0
                 File f = new File(sourcesPath[i]);
 440   
 
 441   
                 // not necessary as JDepend would fail, but why loose
 442   
                 // some time?
 443  0
                 if (!f.exists() || !f.isDirectory()) {
 444  0
                     String msg = "\""
 445   
                         + f.getPath()
 446   
                         + "\" does not represent a valid"
 447   
                         + " directory. JDepend would fail.";
 448  0
                     log(msg);
 449  0
                     throw new BuildException(msg);
 450   
                 }
 451  0
                 try {
 452  0
                     jdepend.addDirectory(f.getPath());
 453   
                 } catch (IOException e) {
 454  0
                     String msg =
 455   
                         "JDepend Failed when adding a source directory: "
 456   
                         + e.getMessage();
 457  0
                     log(msg);
 458  0
                     throw new BuildException(msg);
 459   
                 }
 460   
             }
 461   
         }
 462   
 
 463   
         // This bit turns <exclude> child tags into patters to ignore
 464  0
         String[] patterns = defaultPatterns.getExcludePatterns(getProject());
 465  0
         if (patterns != null && patterns.length > 0) {
 466  0
             if (setFilter != null) {
 467  0
                 Vector v = new Vector();
 468  0
                 for (int i = 0; i < patterns.length; i++) {
 469  0
                     v.addElement(patterns[i]);
 470   
                 }
 471  0
                 try {
 472  0
                     Object o = packageFilterC.newInstance(new Object[] {v});
 473  0
                     setFilter.invoke(jdepend, new Object[] {o});
 474   
                 } catch (Throwable e) {
 475  0
                     log("excludes will be ignored as JDepend doesn't like me: "
 476   
                         + e.getMessage(), Project.MSG_WARN);
 477   
                 }
 478   
             } else {
 479  0
                 log("Sorry, your version of JDepend doesn't support excludes",
 480   
                     Project.MSG_WARN);
 481   
             }
 482   
         }
 483   
 
 484  0
         jdepend.analyze();
 485  0
         return SUCCESS;
 486   
     }
 487   
 
 488   
 
 489   
     /**
 490   
      * Execute the task by forking a new JVM. The command will block until
 491   
      * it finishes. To know if the process was destroyed or not, use the
 492   
      * <tt>killedProcess()</tt> method of the watchdog class.
 493   
      * @param  watchdog   the watchdog in charge of cancelling the test if it
 494   
      * exceeds a certain amount of time. Can be <tt>null</tt>, in this case
 495   
      * the test could probably hang forever.
 496   
      */
 497   
     // JL: comment extracted from JUnitTask (and slightly modified)
 498  0
     public int executeAsForked(CommandlineJava commandline,
 499   
                                ExecuteWatchdog watchdog) throws BuildException {
 500   
         // if not set, auto-create the ClassPath from the project
 501  0
         createClasspath();
 502   
 
 503   
         // not sure whether this test is needed but cost nothing to put.
 504   
         // hope it will be reviewed by anybody competent
 505  0
         if (getClasspath().toString().length() > 0) {
 506  0
             createJvmarg(commandline).setValue("-classpath");
 507  0
             createJvmarg(commandline).setValue(getClasspath().toString());
 508   
         }
 509   
 
 510  0
         if (getOutputFile() != null) {
 511   
             // having a space between the file and its path causes commandline 
 512   
             // to add quotes around the argument thus making JDepend not taking 
 513   
             // it into account. Thus we split it in two
 514  0
             commandline.createArgument().setValue("-file");
 515  0
             commandline.createArgument().setValue(_outputFile.getPath());
 516   
             // we have to find a cleaner way to put this output
 517   
         }
 518   
 
 519   
         // This is deprecated - use classespath in the future
 520  0
         String[] sourcesPath = getSourcespath().list();
 521  0
         for (int i = 0; i < sourcesPath.length; i++) {
 522  0
             File f = new File(sourcesPath[i]);
 523   
 
 524   
             // not necessary as JDepend would fail, but why loose some time?
 525  0
             if (!f.exists() || !f.isDirectory()) {
 526  0
                 throw new BuildException("\"" + f.getPath() + "\" does not " 
 527   
                                          + "represent a valid directory. JDepend would fail.");
 528   
             }
 529  0
             commandline.createArgument().setValue(f.getPath());
 530   
         }
 531   
 
 532   
         // This is the new way - use classespath - code is the same for now
 533  0
         String[] classesPath = getClassespath().list();
 534  0
         for (int i = 0; i < classesPath.length; i++) {
 535  0
             File f = new File(classesPath[i]);
 536   
             // not necessary as JDepend would fail, but why loose some time?
 537  0
             if (!f.exists() || !f.isDirectory()) {
 538  0
                 throw new BuildException("\"" + f.getPath() + "\" does not "
 539   
                                          + "represent a valid directory. JDepend would fail.");
 540   
             }
 541  0
             commandline.createArgument().setValue(f.getPath());
 542   
         }
 543   
 
 544  0
         Execute execute = new Execute(new LogStreamHandler(this, Project.MSG_INFO, Project.MSG_WARN), watchdog);
 545  0
         execute.setCommandline(commandline.getCommandline());
 546  0
         if (getDir() != null) {
 547  0
             execute.setWorkingDirectory(getDir());
 548  0
             execute.setAntRun(getProject());
 549   
         }
 550   
 
 551  0
         if (getOutputFile() != null) {
 552  0
             log("Output to be stored in " + getOutputFile().getPath());
 553   
         }
 554  0
         log(commandline.describeCommand(), Project.MSG_VERBOSE);
 555  0
         try {
 556  0
             return execute.execute();
 557   
         } catch (IOException e) {
 558  0
             throw new BuildException("Process fork failed.", e, getLocation());
 559   
         }
 560   
     }
 561   
 
 562   
     /**
 563   
      * @return <tt>null</tt> if there is a timeout value, otherwise the
 564   
      * watchdog instance.
 565   
      */
 566  0
     protected ExecuteWatchdog createWatchdog() throws BuildException {
 567   
 
 568  0
         return null;
 569   
         /*
 570   
           if (getTimeout() == null){
 571   
           return null;
 572   
           }
 573   
           return new ExecuteWatchdog(getTimeout().intValue());
 574   
         */
 575   
     }
 576   
 }
 577