Clover coverage report - Ant Coverage
Coverage timestamp: Tue Apr 8 2003 20:43:55 EST
file stats: LOC: 500   Methods: 14
NCLOC: 174   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
ProjectHelper.java 30% 38% 50% 37.4%
 1   
 /*
 2   
  * The Apache Software License, Version 1.1
 3   
  *
 4   
  * Copyright (c) 2000-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   
 
 55   
 package org.apache.tools.ant;
 56   
 
 57   
 import java.io.BufferedReader;
 58   
 import java.io.File;
 59   
 import java.io.InputStream;
 60   
 import java.io.InputStreamReader;
 61   
 import java.util.Enumeration;
 62   
 import java.util.Hashtable;
 63   
 import java.util.Locale;
 64   
 import java.util.Vector;
 65   
 import org.apache.tools.ant.helper.ProjectHelper2;
 66   
 import org.apache.tools.ant.util.LoaderUtils;
 67   
 import org.xml.sax.AttributeList;
 68   
 import org.xml.sax.Attributes;
 69   
 
 70   
 /**
 71   
  * Configures a Project (complete with Targets and Tasks) based on
 72   
  * a XML build file. It'll rely on a plugin to do the actual processing
 73   
  * of the xml file.
 74   
  *
 75   
  * This class also provide static wrappers for common introspection.
 76   
  *
 77   
  * All helper plugins must provide backward compatiblity with the
 78   
  * original ant patterns, unless a different behavior is explicitely
 79   
  * specified. For example, if namespace is used on the &lt;project&gt; tag
 80   
  * the helper can expect the entire build file to be namespace-enabled.
 81   
  * Namespaces or helper-specific tags can provide meta-information to
 82   
  * the helper, allowing it to use new ( or different policies ).
 83   
  *
 84   
  * However, if no namespace is used the behavior should be exactly
 85   
  * identical with the default helper.
 86   
  *
 87   
  * @author duncan@x180.com
 88   
  */
 89   
 public class ProjectHelper {
 90   
     /**
 91   
      * Name of JVM system property which provides the name of the
 92   
      * ProjectHelper class to use.
 93   
      */
 94   
     public static final String HELPER_PROPERTY =
 95   
         "org.apache.tools.ant.ProjectHelper";
 96   
 
 97   
     /**
 98   
      * The service identifier in jars which provide Project Helper
 99   
      * implementations.
 100   
      */
 101   
     public static final String SERVICE_ID =
 102   
         "META-INF/services/org.apache.tools.ant.ProjectHelper";
 103   
 
 104   
     /**
 105   
      * Configures the project with the contents of the specified XML file.
 106   
      *
 107   
      * @param project The project to configure. Must not be <code>null</code>.
 108   
      * @param buildFile An XML file giving the project's configuration.
 109   
      *                  Must not be <code>null</code>.
 110   
      *
 111   
      * @deprecated Use the non-statuc parse method
 112   
      * @exception BuildException if the configuration is invalid or cannot
 113   
      *                           be read
 114   
      */
 115  566
     public static void configureProject(Project project, File buildFile)
 116   
         throws BuildException {
 117  566
         ProjectHelper helper = ProjectHelper.getProjectHelper();
 118  566
         project.addReference("ant.projectHelper", helper);
 119  566
         helper.parse(project, buildFile);
 120   
     }
 121   
 
 122   
     /** Default constructor */
 123  575
     public ProjectHelper() {
 124   
     }
 125   
 
 126   
     // -------------------- Common properties  --------------------
 127   
     // The following properties are required by import ( and other tasks
 128   
     // that read build files using ProjectHelper ).
 129   
 
 130   
     // A project helper may process multiple files. We'll keep track
 131   
     // of them - to avoid loops and to allow caching. The caching will
 132   
     // probably accelerate things like <antCall>.
 133   
     // The key is the absolute file, the value is a processed tree.
 134   
     // Since the tree is composed of UE and RC - it can be reused !
 135   
     // protected Hashtable processedFiles=new Hashtable();
 136   
 
 137   
     protected Vector importStack=new Vector();
 138   
 
 139   
     // Temporary - until we figure a better API
 140   
     /** EXPERIMENTAL WILL_CHANGE
 141   
      *
 142   
      */
 143   
 //    public Hashtable getProcessedFiles() {
 144   
 //        return processedFiles;
 145   
 //    }
 146   
 
 147   
     /** EXPERIMENTAL WILL_CHANGE
 148   
      *  Import stack.
 149   
      *  Used to keep track of imported files. Error reporting should
 150   
      *  display the import path.
 151   
      */
 152  1132
     public Vector getImportStack() {
 153  1132
         return importStack;
 154   
     }
 155   
 
 156   
 
 157   
     // --------------------  Parse method  --------------------
 158   
     /**
 159   
      * Parses the project file, configuring the project as it goes.
 160   
      *
 161   
      * @param project The project for the resulting ProjectHelper to configure.
 162   
      *                Must not be <code>null</code>.
 163   
      * @param source The source for XML configuration. A helper must support
 164   
      *               at least File, for backward compatibility. Helpers may
 165   
      *               support URL, InputStream, etc or specialized types.
 166   
      *
 167   
      * @since Ant1.5
 168   
      * @exception BuildException if the configuration is invalid or cannot
 169   
      *                           be read
 170   
      */
 171  0
     public void parse(Project project, Object source) throws BuildException {
 172  0
         throw new BuildException("ProjectHelper.parse() must be implemented "
 173   
             + "in a helper plugin " + this.getClass().getName());
 174   
     }
 175   
 
 176   
 
 177   
     /**
 178   
      * Discovers a project helper instance. Uses the same patterns
 179   
      * as JAXP, commons-logging, etc: a system property, a JDK1.3
 180   
      * service discovery, default.
 181   
      *
 182   
      * @return a ProjectHelper, either a custom implementation
 183   
      * if one is available and configured, or the default implementation
 184   
      * otherwise.
 185   
      *
 186   
      * @exception BuildException if a specified helper class cannot
 187   
      * be loaded/instantiated.
 188   
      */
 189  575
     public static ProjectHelper getProjectHelper()
 190   
         throws BuildException {
 191   
         // Identify the class loader we will be using. Ant may be
 192   
         // in a webapp or embeded in a different app
 193  575
         ProjectHelper helper = null;
 194   
 
 195   
         // First, try the system property
 196  575
         String helperClass = System.getProperty(HELPER_PROPERTY);
 197  575
         try {
 198  575
             if (helperClass != null) {
 199  0
                 helper = newHelper(helperClass);
 200   
             }
 201   
         } catch (SecurityException e) {
 202  0
             System.out.println("Unable to load ProjectHelper class \""
 203   
                 + helperClass + " specified in system property "
 204   
                 + HELPER_PROPERTY);
 205   
         }
 206   
 
 207   
         // A JDK1.3 'service' ( like in JAXP ). That will plug a helper
 208   
         // automatically if in CLASSPATH, with the right META-INF/services.
 209  575
         if (helper == null) {
 210  575
             try {
 211  575
                 ClassLoader classLoader = LoaderUtils.getContextClassLoader();
 212  575
                 InputStream is = null;
 213  575
                 if (classLoader != null) {
 214  575
                     is = classLoader.getResourceAsStream(SERVICE_ID);
 215   
                 }
 216  575
                 if (is == null) {
 217  575
                     is = ClassLoader.getSystemResourceAsStream(SERVICE_ID);
 218   
                 }
 219   
 
 220  575
                 if (is != null) {
 221   
                     // This code is needed by EBCDIC and other strange systems.
 222   
                     // It's a fix for bugs reported in xerces
 223  0
                     InputStreamReader isr;
 224  0
                     try {
 225  0
                         isr = new InputStreamReader(is, "UTF-8");
 226   
                     } catch (java.io.UnsupportedEncodingException e) {
 227  0
                         isr = new InputStreamReader(is);
 228   
                     }
 229  0
                     BufferedReader rd = new BufferedReader(isr);
 230   
 
 231  0
                     String helperClassName = rd.readLine();
 232  0
                     rd.close();
 233   
 
 234  0
                     if (helperClassName != null &&
 235   
                         !"".equals(helperClassName)) {
 236   
 
 237  0
                         helper = newHelper(helperClassName);
 238   
                     }
 239   
                 }
 240   
             } catch (Exception ex) {
 241  0
                 System.out.println("Unable to load ProjectHelper "
 242   
                     + "from service \"" + SERVICE_ID);
 243   
             }
 244   
         }
 245   
 
 246  575
         if (helper != null) {
 247  0
             return helper;
 248   
         } else {
 249  575
             try {
 250   
                 // Default
 251   
                 // return new ProjectHelperImpl();
 252  575
                 return new ProjectHelper2();
 253   
             } catch (Throwable e) {
 254  0
                 String message = "Unable to load default ProjectHelper due to "
 255   
                     + e.getClass().getName() + ": " + e.getMessage();
 256  0
                 throw new BuildException(message, e);
 257   
             }
 258   
         }
 259   
     }
 260   
 
 261   
     /**
 262   
      * Creates a new helper instance from the name of the class.
 263   
      * It'll first try the thread class loader, then Class.forName()
 264   
      * will load from the same loader that loaded this class.
 265   
      *
 266   
      * @param helperClass The name of the class to create an instance
 267   
      *                    of. Must not be <code>null</code>.
 268   
      *
 269   
      * @return a new instance of the specified class.
 270   
      *
 271   
      * @exception BuildException if the class cannot be found or
 272   
      * cannot be appropriate instantiated.
 273   
      */
 274  0
     private static ProjectHelper newHelper(String helperClass)
 275   
         throws BuildException {
 276  0
         ClassLoader classLoader = LoaderUtils.getContextClassLoader();
 277  0
         try {
 278  0
             Class clazz = null;
 279  0
             if (classLoader != null) {
 280  0
                 try {
 281  0
                     clazz = classLoader.loadClass(helperClass);
 282   
                 } catch (ClassNotFoundException ex) {
 283   
                     // try next method
 284   
                 }
 285   
             }
 286  0
             if (clazz == null) {
 287  0
                 clazz = Class.forName(helperClass);
 288   
             }
 289  0
             return ((ProjectHelper) clazz.newInstance());
 290   
         } catch (Exception e) {
 291  0
             throw new BuildException(e);
 292   
         }
 293   
     }
 294   
 
 295   
     /**
 296   
      * JDK1.1 compatible access to the context class loader.
 297   
      * Cut&paste from JAXP.
 298   
      *
 299   
      * @deprecated Use LoaderUtils.getContextClassLoader()
 300   
      * @return the current context class loader, or <code>null</code>
 301   
      * if the context class loader is unavailable.
 302   
      */
 303  0
     public static ClassLoader getContextClassLoader() {
 304  0
         if (!LoaderUtils.isContextLoaderAvailable()) {
 305  0
             return null;
 306   
         }
 307   
 
 308  0
         return LoaderUtils.getContextClassLoader();
 309   
     }
 310   
 
 311   
     // -------------------- Static utils, used by most helpers ----------------
 312   
 
 313   
     /**
 314   
      * Configures an object using an introspection handler.
 315   
      *
 316   
      * @param target The target object to be configured.
 317   
      *               Must not be <code>null</code>.
 318   
      * @param attrs  A list of attributes to configure within the target.
 319   
      *               Must not be <code>null</code>.
 320   
      * @param project The project containing the target.
 321   
      *                Must not be <code>null</code>.
 322   
      *
 323   
      * @deprecated Use IntrospectionHelper for each property
 324   
      * @exception BuildException if any of the attributes can't be handled by
 325   
      *                           the target
 326   
      */
 327  0
     public static void configure(Object target, AttributeList attrs,
 328   
                                  Project project) throws BuildException {
 329  0
         if (target instanceof TaskAdapter) {
 330  0
             target = ((TaskAdapter) target).getProxy();
 331   
         }
 332   
 
 333  0
         IntrospectionHelper ih =
 334   
             IntrospectionHelper.getHelper(target.getClass());
 335   
 
 336  0
         project.addBuildListener(ih);
 337   
 
 338  0
         for (int i = 0; i < attrs.getLength(); i++) {
 339   
             // reflect these into the target
 340  0
             String value = replaceProperties(project, attrs.getValue(i),
 341   
                                            project.getProperties());
 342  0
             try {
 343  0
                 ih.setAttribute(project, target,
 344   
                                 attrs.getName(i).toLowerCase(Locale.US), value);
 345   
 
 346   
             } catch (BuildException be) {
 347   
                 // id attribute must be set externally
 348  0
                 if (!attrs.getName(i).equals("id")) {
 349  0
                     throw be;
 350   
                 }
 351   
             }
 352   
         }
 353   
     }
 354   
 
 355   
     /**
 356   
      * Adds the content of #PCDATA sections to an element.
 357   
      *
 358   
      * @param project The project containing the target.
 359   
      *                Must not be <code>null</code>.
 360   
      * @param target  The target object to be configured.
 361   
      *                Must not be <code>null</code>.
 362   
      * @param buf A character array of the text within the element.
 363   
      *            Will not be <code>null</code>.
 364   
      * @param start The start element in the array.
 365   
      * @param count The number of characters to read from the array.
 366   
      *
 367   
      * @exception BuildException if the target object doesn't accept text
 368   
      */
 369  0
     public static void addText(Project project, Object target, char[] buf,
 370   
         int start, int count) throws BuildException {
 371  0
         addText(project, target, new String(buf, start, count));
 372   
     }
 373   
 
 374   
     /**
 375   
      * Adds the content of #PCDATA sections to an element.
 376   
      *
 377   
      * @param project The project containing the target.
 378   
      *                Must not be <code>null</code>.
 379   
      * @param target  The target object to be configured.
 380   
      *                Must not be <code>null</code>.
 381   
      * @param text    Text to add to the target.
 382   
      *                May be <code>null</code>, in which case this
 383   
      *                method call is a no-op.
 384   
      *
 385   
      * @exception BuildException if the target object doesn't accept text
 386   
      */
 387  673
     public static void addText(Project project, Object target, String text)
 388   
         throws BuildException {
 389   
 
 390  673
         if (text == null) {
 391  0
             return;
 392   
         }
 393   
 
 394  673
         if (target instanceof TaskAdapter) {
 395  63
             target = ((TaskAdapter) target).getProxy();
 396   
         }
 397   
 
 398  673
         IntrospectionHelper.getHelper(target.getClass()).addText(project,
 399   
             target, text);
 400   
     }
 401   
 
 402   
     /**
 403   
      * Stores a configured child element within its parent object.
 404   
      *
 405   
      * @param project Project containing the objects.
 406   
      *                May be <code>null</code>.
 407   
      * @param parent  Parent object to add child to.
 408   
      *                Must not be <code>null</code>.
 409   
      * @param child   Child object to store in parent.
 410   
      *                Should not be <code>null</code>.
 411   
      * @param tag     Name of element which generated the child.
 412   
      *                May be <code>null</code>, in which case
 413   
      *                the child is not stored.
 414   
      */
 415  842
     public static void storeChild(Project project, Object parent,
 416   
          Object child, String tag) {
 417  842
         IntrospectionHelper ih
 418   
             = IntrospectionHelper.getHelper(parent.getClass());
 419  842
         ih.storeElement(project, parent, child, tag);
 420   
     }
 421   
 
 422   
     /**
 423   
      * Replaces <code>${xxx}</code> style constructions in the given value with
 424   
      * the string value of the corresponding properties.
 425   
      *
 426   
      * @param project The project containing the properties to replace.
 427   
      *                Must not be <code>null</code>.
 428   
      *
 429   
      * @param value The string to be scanned for property references.
 430   
      *              May be <code>null</code>.
 431   
      *
 432   
      * @exception BuildException if the string contains an opening
 433   
      *                           <code>${</code> without a closing
 434   
      *                           <code>}</code>
 435   
      * @return the original string with the properties replaced, or
 436   
      *         <code>null</code> if the original string is <code>null</code>.
 437   
      *
 438   
      * @deprecated Use project.replaceProperties()
 439   
      * @since 1.5
 440   
      */
 441  0
      public static String replaceProperties(Project project, String value)
 442   
             throws BuildException {
 443   
         // needed since project properties are not accessible
 444  0
          return project.replaceProperties(value);
 445   
      }
 446   
 
 447   
     /**
 448   
      * Replaces <code>${xxx}</code> style constructions in the given value
 449   
      * with the string value of the corresponding data types.
 450   
      *
 451   
      * @param project The container project. This is used solely for
 452   
      *                logging purposes. Must not be <code>null</code>.
 453   
      * @param value The string to be scanned for property references.
 454   
      *              May be <code>null</code>, in which case this
 455   
      *              method returns immediately with no effect.
 456   
      * @param keys  Mapping (String to String) of property names to their
 457   
      *              values. Must not be <code>null</code>.
 458   
      *
 459   
      * @exception BuildException if the string contains an opening
 460   
      *                           <code>${</code> without a closing
 461   
      *                           <code>}</code>
 462   
      * @return the original string with the properties replaced, or
 463   
      *         <code>null</code> if the original string is <code>null</code>.
 464   
      * @deprecated Use PropertyHelper
 465   
      */
 466  0
      public static String replaceProperties(Project project, String value,
 467   
          Hashtable keys) throws BuildException
 468   
     {
 469  0
         PropertyHelper ph=PropertyHelper.getPropertyHelper(project);
 470  0
         return ph.replaceProperties( null, value, keys);
 471   
     }
 472   
 
 473   
     /**
 474   
      * Parses a string containing <code>${xxx}</code> style property
 475   
      * references into two lists. The first list is a collection
 476   
      * of text fragments, while the other is a set of string property names.
 477   
      * <code>null</code> entries in the first list indicate a property
 478   
      * reference from the second list.
 479   
      *
 480   
      * @param value     Text to parse. Must not be <code>null</code>.
 481   
      * @param fragments List to add text fragments to.
 482   
      *                  Must not be <code>null</code>.
 483   
      * @param propertyRefs List to add property names to.
 484   
      *                     Must not be <code>null</code>.
 485   
      *
 486   
      * @deprecated Use PropertyHelper
 487   
      * @exception BuildException if the string contains an opening
 488   
      *                           <code>${</code> without a closing
 489   
      *                           <code>}</code>
 490   
      */
 491  123
     public static void parsePropertyString(String value, Vector fragments,
 492   
                                            Vector propertyRefs)
 493   
         throws BuildException
 494   
     {
 495  123
         PropertyHelper.parsePropertyStringDefault(value, fragments,
 496   
                 propertyRefs);
 497   
     }
 498   
 //end class
 499   
 }
 500