Clover coverage report - Ant Coverage
Coverage timestamp: Tue Apr 8 2003 20:43:55 EST
file stats: LOC: 400   Methods: 20
NCLOC: 214   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
Definer.java 36% 43.9% 45% 41.7%
 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;
 56   
 
 57   
 import java.io.File;
 58   
 import java.io.FileInputStream;
 59   
 import java.io.IOException;
 60   
 import java.io.InputStream;
 61   
 import java.util.Enumeration;
 62   
 import java.util.Properties;
 63   
 import org.apache.tools.ant.AntClassLoader;
 64   
 import org.apache.tools.ant.BuildException;
 65   
 import org.apache.tools.ant.Project;
 66   
 import org.apache.tools.ant.Task;
 67   
 import org.apache.tools.ant.types.Path;
 68   
 import org.apache.tools.ant.types.Reference;
 69   
 
 70   
 /**
 71   
  * Base class for Taskdef and Typedef - does all the classpath
 72   
  * handling and and class loading.
 73   
  *
 74   
  * @author Costin Manolache
 75   
  * @author Stefan Bodewig
 76   
  *
 77   
  * @since Ant 1.4
 78   
  */
 79   
 public abstract class Definer extends Task {
 80   
     private String name;
 81   
     private String value;
 82   
     private Path classpath;
 83   
     private File file;
 84   
     private String resource;
 85   
     private boolean reverseLoader = false;
 86   
     private String loaderId = null;
 87   
     private String classpathId = null;
 88   
 
 89   
     private static final String REUSE_LOADER_REF = "ant.reuse.loader";
 90   
 
 91   
     /**
 92   
      * @deprecated stop using this attribute
 93   
      * @ant.attribute ignore="true"
 94   
      */
 95  0
     public void setReverseLoader(boolean reverseLoader) {
 96  0
         this.reverseLoader = reverseLoader;
 97  0
         log("The reverseloader attribute is DEPRECATED. It will be removed",
 98   
             Project.MSG_WARN);
 99   
     }
 100   
 
 101  0
     public String getName() {
 102  0
         return name;
 103   
     }
 104   
 
 105  0
     public Path getClasspath() {
 106  0
         return classpath;
 107   
     }
 108   
 
 109  0
     public File getFile() {
 110  0
         return file;
 111   
     }
 112   
 
 113  0
     public String getResource() {
 114  0
         return resource;
 115   
     }
 116   
 
 117  0
     public boolean isReverseLoader() {
 118  0
         return reverseLoader;
 119   
     }
 120   
 
 121  0
     public String getLoaderId() {
 122  0
         return loaderId;
 123   
     }
 124   
 
 125  0
     public String getClasspathId() {
 126  0
         return classpathId;
 127   
     }
 128   
 
 129   
     /**
 130   
      * Set the classpath to be used when searching for component being defined
 131   
      *
 132   
      * @param classpath an Ant Path object containing the classpath.
 133   
      */
 134  2
     public void setClasspath(Path classpath) {
 135  2
         if (this.classpath == null) {
 136  2
             this.classpath = classpath;
 137   
         } else {
 138  0
             this.classpath.append(classpath);
 139   
         }
 140   
     }
 141   
 
 142   
     /**
 143   
      * Create the classpath to be used when searching for component being defined
 144   
      */
 145  22
     public Path createClasspath() {
 146  22
         if (this.classpath == null) {
 147  22
             this.classpath = new Path(getProject());
 148   
         }
 149  22
         return this.classpath.createPath();
 150   
     }
 151   
 
 152   
     /**
 153   
      * reference to a classpath to use when loading the files.
 154   
      * To actually share the same loader, set loaderref as well
 155   
      */
 156  1
     public void setClasspathRef(Reference r) {
 157  1
         classpathId=r.getRefId();
 158  1
         createClasspath().setRefid(r);
 159   
     }
 160   
 
 161   
     /**
 162   
      * Use the reference to locate the loader. If the loader is not
 163   
      * found, taskdef will use the specified classpath and register it
 164   
      * with the specified name.
 165   
      *
 166   
      * This allow multiple taskdef/typedef to use the same class loader,
 167   
      * so they can be used together. It eliminate the need to
 168   
      * put them in the CLASSPATH.
 169   
      *
 170   
      * @since Ant 1.5
 171   
      */
 172  1
     public void setLoaderRef(Reference r) {
 173  1
         loaderId = r.getRefId();
 174   
     }
 175   
 
 176   
 
 177  39
     public void execute() throws BuildException {
 178  39
         ClassLoader al = createLoader();
 179   
 
 180  38
         if (file == null && resource == null) {
 181   
 
 182   
             // simple case - one definition
 183  38
             if (name == null || value == null) {
 184  6
                 String msg = "name or classname attributes of "
 185   
                     + getTaskName() + " element "
 186   
                     + "are undefined";
 187  6
                 throw new BuildException(msg);
 188   
             }
 189  32
             addDefinition(al, name, value);
 190   
 
 191   
         } else {
 192   
 
 193  0
             InputStream is = null;
 194  0
             try {
 195  0
                 if (name != null || value != null) {
 196  0
                     String msg = "You must not specify name or value "
 197   
                         + "together with file or resource.";
 198  0
                     throw new BuildException(msg, getLocation());
 199   
                 }
 200   
 
 201  0
                 if (file != null && resource != null) {
 202  0
                     String msg = "You must not specify both, file and "
 203   
                         + "resource.";
 204  0
                     throw new BuildException(msg, getLocation());
 205   
                 }
 206   
 
 207   
 
 208  0
                 Properties props = new Properties();
 209  0
                 if (file != null) {
 210  0
                     log("Loading definitions from file " + file,
 211   
                         Project.MSG_VERBOSE);
 212  0
                     is = new FileInputStream(file);
 213  0
                     if (is == null) {
 214  0
                         log("Could not load definitions from file " + file
 215   
                             + ". It doesn\'t exist.", Project.MSG_WARN);
 216   
                     }
 217   
                 }
 218  0
                 if (resource != null) {
 219  0
                     log("Loading definitions from resource " + resource,
 220   
                         Project.MSG_VERBOSE);
 221  0
                     is = al.getResourceAsStream(resource);
 222  0
                     if (is == null) {
 223  0
                         log("Could not load definitions from resource "
 224   
                             + resource + ". It could not be found.",
 225   
                             Project.MSG_WARN);
 226   
                     }
 227   
                 }
 228   
 
 229  0
                 if (is != null) {
 230  0
                     props.load(is);
 231  0
                     Enumeration keys = props.keys();
 232  0
                     while (keys.hasMoreElements()) {
 233  0
                         String n = (String) keys.nextElement();
 234  0
                         String v = props.getProperty(n);
 235  0
                         addDefinition(al, n, v);
 236   
                     }
 237   
                 }
 238   
             } catch (IOException ex) {
 239  0
                 throw new BuildException(ex, getLocation());
 240   
             } finally {
 241  0
                 if (is != null) {
 242  0
                     try {
 243  0
                         is.close();
 244   
                     } catch (IOException e) {}
 245   
                 }
 246   
             }
 247   
         }
 248   
     }
 249   
 
 250   
     /**
 251   
      * create the classloader then hand the definition off to the subclass;
 252   
      * @throws BuildException when the class wont load for any reason
 253   
      */
 254  32
     private void addDefinition(ClassLoader al, String name, String value)
 255   
         throws BuildException {
 256  32
         try {
 257  32
             Class c = al.loadClass(value);
 258  30
             AntClassLoader.initializeClass(c);
 259  30
             addDefinition(name, c);
 260   
         } catch (ClassNotFoundException cnfe) {
 261  2
             String msg = getTaskName() + " class " + value
 262   
                 + " cannot be found";
 263  2
             throw new BuildException(msg, cnfe, getLocation());
 264   
         } catch (NoClassDefFoundError ncdfe) {
 265  0
             String msg = getTaskName() + "A class needed on loading by class "
 266   
                 + value + " cannot be found: " + ncdfe.getMessage();
 267  0
             throw new BuildException(msg, ncdfe, location);
 268   
         }
 269   
     }
 270   
 
 271   
     /**
 272   
      * create a classloader for this definition
 273   
      */
 274  39
     private ClassLoader createLoader() {
 275   
         // magic property
 276  39
         if (getProject().getProperty(REUSE_LOADER_REF) != null) {
 277   
             // Generate the 'reuse' name automatically from the reference.
 278   
             // This allows <taskdefs> that work on both ant1.4 and ant1.5.
 279   
             // ( in 1.4 it'll require the task/type to be in classpath if they
 280   
             //   are used togheter ).
 281  0
             if (loaderId == null && classpathId != null) {
 282  0
                 loaderId = "ant.loader." + classpathId;
 283   
             }
 284   
         }
 285   
 
 286   
         // If a loader has been set ( either by loaderRef or magic property )
 287  39
         if (loaderId != null) {
 288  1
             Object reusedLoader = getProject().getReference(loaderId);
 289  1
             if (reusedLoader != null) {
 290  1
                 if (!(reusedLoader instanceof ClassLoader)) {
 291  1
                     throw new BuildException("The specified loader id " +
 292   
                         loaderId + " does not reference a class loader");
 293   
                 }
 294   
 
 295  0
                 return (ClassLoader)reusedLoader;
 296   
                 //if (reusedLoader instanceof AntClassLoader) {
 297   
                 //    return (AntClassLoader)reusedLoader;
 298   
                 //}
 299   
                 // In future the reference object may be the <loader> type
 300   
                 // if (reusedLoader instanceof Loader ) {
 301   
                 //      return ((Loader)reusedLoader).getLoader(project);
 302   
                 // }
 303   
             }
 304   
         }
 305   
 
 306  38
         ClassLoader al = null;
 307   
 
 308  38
         if (classpath == null) {
 309   
             // do we need to create another loader ?
 310  15
             al=project.getCoreLoader();
 311  15
             if (al != null ) {
 312  0
                 return al;
 313   
             }
 314   
         }
 315   
 
 316  38
         if (classpath != null) {
 317  23
             project.log( "Creating new loader for taskdef using " + classpath +
 318   
                     " reverse=" + reverseLoader, Project.MSG_DEBUG );
 319  23
             AntClassLoader acl = getProject().createClassLoader(classpath);
 320  23
             if (reverseLoader) {
 321  0
                 acl.setParentFirst(false);
 322  0
                 acl.addJavaLibraries();
 323   
             }
 324  23
             al = acl;
 325   
         } else {
 326   
             // XXX Probably it would be better to reuse getClass().getClassLoader()
 327   
             // I don't think we need a new ( identical ) loader for each task
 328  15
             AntClassLoader acl
 329   
                 = getProject().createClassLoader(Path.systemClasspath);
 330  15
             if (reverseLoader) {
 331  0
                 acl.setParentFirst(false);
 332  0
                 acl.addJavaLibraries();
 333   
             }
 334  15
             al = acl;
 335   
         }
 336   
         // need to load Task via system classloader or the new
 337   
         // task we want to define will never be a Task but always
 338   
         // be wrapped into a TaskAdapter.
 339  38
         ((AntClassLoader)al).addSystemPackageRoot("org.apache.tools.ant");
 340   
 
 341   
 
 342   
         // If the loader is new, record it for future uses by other
 343   
         // task/typedefs
 344  38
         if (loaderId != null) {
 345  0
             if (getProject().getReference(loaderId) == null) {
 346  0
                 getProject().addReference(loaderId, al);
 347   
             }
 348   
         }
 349   
 
 350  38
         return al;
 351   
     }
 352   
 
 353   
     /**
 354   
      * Name of the property file  to load
 355   
      * ant name/classname pairs from.
 356   
      */
 357  0
     public void setFile(File file) {
 358  0
         this.file = file;
 359   
     }
 360   
 
 361   
     /**
 362   
      * Name of the property resource to load
 363   
      * ant name/classname pairs from.
 364   
      */
 365  0
     public void setResource(String res) {
 366  0
         this.resource = res;
 367   
     }
 368   
 
 369   
     /**
 370   
      * Name of the property resource to load
 371   
      * ant name/classname pairs from.
 372   
      */
 373  34
     public void setName(String name) {
 374  34
         this.name = name;
 375   
     }
 376   
 
 377   
     /**
 378   
      * Returns the classname of the object we are defining.
 379   
      * May be <code>null</code>.
 380   
      */
 381  0
     public String getClassname() {
 382  0
         return value;
 383   
     }
 384   
 
 385   
     /**
 386   
      * The full class name of the object being defined.
 387   
      * Required, unless file or resource have
 388   
      * been specified.
 389   
      */
 390  35
     public void setClassname(String v) {
 391  35
         value = v;
 392   
     }
 393   
 
 394   
     /**
 395   
      * This must be implemented by subclasses; it is the callback
 396   
      * they will get to add a new definition of their type.
 397   
      */
 398   
     protected abstract void addDefinition(String name, Class c);
 399   
 }
 400