Home » apache-ant-1.7.1-src » org.apache.tools » ant » taskdefs » [javadoc | source]
    1   /*
    2    *  Licensed to the Apache Software Foundation (ASF) under one or more
    3    *  contributor license agreements.  See the NOTICE file distributed with
    4    *  this work for additional information regarding copyright ownership.
    5    *  The ASF licenses this file to You under the Apache License, Version 2.0
    6    *  (the "License"); you may not use this file except in compliance with
    7    *  the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    *  Unless required by applicable law or agreed to in writing, software
   12    *  distributed under the License is distributed on an "AS IS" BASIS,
   13    *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    *  See the License for the specific language governing permissions and
   15    *  limitations under the License.
   16    *
   17    */
   18   
   19   package org.apache.tools.ant.taskdefs;
   20   
   21   import java.io.File;
   22   import java.io.FileInputStream;
   23   import java.io.IOException;
   24   import java.io.InputStream;
   25   import java.net.URL;
   26   import java.util.Enumeration;
   27   import java.util.Properties;
   28   import java.util.Stack;
   29   import java.util.Vector;
   30   
   31   import org.apache.tools.ant.BuildException;
   32   import org.apache.tools.ant.Project;
   33   import org.apache.tools.ant.PropertyHelper;
   34   import org.apache.tools.ant.Task;
   35   import org.apache.tools.ant.types.Path;
   36   import org.apache.tools.ant.types.Reference;
   37   
   38   /**
   39    * Sets a property by name, or set of properties (from file or
   40    * resource) in the project.  </p>
   41    * Properties are immutable: whoever sets a property first freezes it for the
   42    * rest of the build; they are most definitely not variable.
   43    * <p>There are five ways to set properties:</p>
   44    * <ul>
   45    *   <li>By supplying both the <i>name</i> and <i>value</i> attribute.</li>
   46    *   <li>By supplying both the <i>name</i> and <i>refid</i> attribute.</li>
   47    *   <li>By setting the <i>file</i> attribute with the filename of the property
   48    *     file to load. This property file has the format as defined by the file used
   49    *     in the class java.util.Properties.</li>
   50    *   <li>By setting the <i>resource</i> attribute with the resource name of the
   51    *     property file to load. This property file has the format as defined by the
   52    *     file used in the class java.util.Properties.</li>
   53    *   <li>By setting the <i>environment</i> attribute with a prefix to use.
   54    *     Properties will be defined for every environment variable by
   55    *     prefixing the supplied name and a period to the name of the variable.</li>
   56    * </ul>
   57    * <p>Although combinations of these ways are possible, only one should be used
   58    * at a time. Problems might occur with the order in which properties are set, for
   59    * instance.</p>
   60    * <p>The value part of the properties being set, might contain references to other
   61    * properties. These references are resolved at the time these properties are set.
   62    * This also holds for properties loaded from a property file.</p>
   63    * Properties are case sensitive.
   64    *
   65    * @since Ant 1.1
   66    *
   67    * @ant.attribute.group name="name" description="One of these, when using the name attribute"
   68    * @ant.attribute.group name="noname" description="One of these, when not using the name attribute"
   69    * @ant.task category="property"
   70    */
   71   public class Property extends Task {
   72   
   73       // CheckStyle:VisibilityModifier OFF - bc
   74       protected String name;
   75       protected String value;
   76       protected File file;
   77       protected URL url;
   78       protected String resource;
   79       protected Path classpath;
   80       protected String env;
   81       protected Reference ref;
   82       protected String prefix;
   83       private Project fallback;
   84   
   85       protected boolean userProperty; // set read-only properties
   86       // CheckStyle:VisibilityModifier ON
   87   
   88       /**
   89        * Constructor for Property.
   90        */
   91       public Property() {
   92           this(false);
   93       }
   94   
   95       /**
   96        * Constructor for Property.
   97        * @param userProperty if true this is a user property
   98        * @since Ant 1.5
   99        */
  100       protected Property(boolean userProperty) {
  101           this(userProperty, null);
  102       }
  103   
  104       /**
  105        * Constructor for Property.
  106        * @param userProperty if true this is a user property
  107        * @param fallback a project to use to look for references if the reference is
  108        *                 not in the current project
  109        * @since Ant 1.5
  110        */
  111       protected Property(boolean userProperty, Project fallback) {
  112           this.userProperty = userProperty;
  113           this.fallback = fallback;
  114       }
  115   
  116       /**
  117        * The name of the property to set.
  118        * @param name property name
  119        */
  120       public void setName(String name) {
  121           this.name = name;
  122       }
  123   
  124       /**
  125        * Get the property name.
  126        * @return the property name
  127        */
  128       public String getName() {
  129           return name;
  130       }
  131   
  132       /**
  133        * Sets the property to the absolute filename of the
  134        * given file. If the value of this attribute is an absolute path, it
  135        * is left unchanged (with / and \ characters converted to the
  136        * current platforms conventions). Otherwise it is taken as a path
  137        * relative to the project's basedir and expanded.
  138        * @param location path to set
  139        *
  140        * @ant.attribute group="name"
  141        */
  142       public void setLocation(File location) {
  143           setValue(location.getAbsolutePath());
  144       }
  145   
  146       /**
  147        * The value of the property.
  148        * @param value value to assign
  149        *
  150        * @ant.attribute group="name"
  151        */
  152       public void setValue(String value) {
  153           this.value = value;
  154       }
  155   
  156       /**
  157        * Get the property value.
  158        * @return the property value
  159        */
  160       public String getValue() {
  161           return value;
  162       }
  163   
  164       /**
  165        * Filename of a property file to load.
  166        * @param file filename
  167        *
  168        * @ant.attribute group="noname"
  169        */
  170       public void setFile(File file) {
  171           this.file = file;
  172       }
  173   
  174       /**
  175        * Get the file attribute.
  176        * @return the file attribute
  177        */
  178       public File getFile() {
  179           return file;
  180       }
  181   
  182       /**
  183        * The url from which to load properties.
  184        * @param url url string
  185        *
  186        * @ant.attribute group="noname"
  187        */
  188       public void setUrl(URL url) {
  189           this.url = url;
  190       }
  191   
  192       /**
  193        * Get the url attribute.
  194        * @return the url attribute
  195        */
  196       public URL getUrl() {
  197           return url;
  198       }
  199   
  200       /**
  201        * Prefix to apply to properties loaded using <code>file</code>
  202        * or <code>resource</code>.
  203        * A "." is appended to the prefix if not specified.
  204        * @param prefix prefix string
  205        * @since Ant 1.5
  206        */
  207       public void setPrefix(String prefix) {
  208           this.prefix = prefix;
  209           if (!prefix.endsWith(".")) {
  210               this.prefix += ".";
  211           }
  212       }
  213   
  214       /**
  215        * Get the prefix attribute.
  216        * @return the prefix attribute
  217        * @since Ant 1.5
  218        */
  219       public String getPrefix() {
  220           return prefix;
  221       }
  222   
  223       /**
  224        * Sets a reference to an Ant datatype
  225        * declared elsewhere.
  226        * Only yields reasonable results for references
  227        * PATH like structures or properties.
  228        * @param ref reference
  229        *
  230        * @ant.attribute group="name"
  231        */
  232       public void setRefid(Reference ref) {
  233           this.ref = ref;
  234       }
  235   
  236       /**
  237        * Get the refid attribute.
  238        * @return the refid attribute
  239        */
  240       public Reference getRefid() {
  241           return ref;
  242       }
  243   
  244       /**
  245        * The resource name of a property file to load
  246        * @param resource resource on classpath
  247        *
  248        * @ant.attribute group="noname"
  249        */
  250       public void setResource(String resource) {
  251           this.resource = resource;
  252       }
  253   
  254       /**
  255        * Get the resource attribute.
  256        * @return the resource attribute
  257        */
  258       public String getResource() {
  259           return resource;
  260       }
  261   
  262       /**
  263        * Prefix to use when retrieving environment variables.
  264        * Thus if you specify environment=&quot;myenv&quot;
  265        * you will be able to access OS-specific
  266        * environment variables via property names &quot;myenv.PATH&quot; or
  267        * &quot;myenv.TERM&quot;.
  268        * <p>
  269        * Note that if you supply a property name with a final
  270        * &quot;.&quot; it will not be doubled. ie environment=&quot;myenv.&quot; will still
  271        * allow access of environment variables through &quot;myenv.PATH&quot; and
  272        * &quot;myenv.TERM&quot;. This functionality is currently only implemented
  273        * on select platforms. Feel free to send patches to increase the number of platforms
  274        * this functionality is supported on ;).<br>
  275        * Note also that properties are case sensitive, even if the
  276        * environment variables on your operating system are not, e.g. it
  277        * will be ${env.Path} not ${env.PATH} on Windows 2000.
  278        * @param env prefix
  279        *
  280        * @ant.attribute group="noname"
  281        */
  282       public void setEnvironment(String env) {
  283           this.env = env;
  284       }
  285   
  286       /**
  287        * Get the environment attribute.
  288        * @return the environment attribute
  289        * @since Ant 1.5
  290        */
  291       public String getEnvironment() {
  292           return env;
  293       }
  294   
  295       /**
  296        * The classpath to use when looking up a resource.
  297        * @param classpath to add to any existing classpath
  298        */
  299       public void setClasspath(Path classpath) {
  300           if (this.classpath == null) {
  301               this.classpath = classpath;
  302           } else {
  303               this.classpath.append(classpath);
  304           }
  305       }
  306   
  307       /**
  308        * The classpath to use when looking up a resource.
  309        * @return a path to be configured
  310        */
  311       public Path createClasspath() {
  312           if (this.classpath == null) {
  313               this.classpath = new Path(getProject());
  314           }
  315           return this.classpath.createPath();
  316       }
  317   
  318       /**
  319        * the classpath to use when looking up a resource,
  320        * given as reference to a &lt;path&gt; defined elsewhere
  321        * @param r a reference to a classpath
  322        */
  323       public void setClasspathRef(Reference r) {
  324           createClasspath().setRefid(r);
  325       }
  326   
  327       /**
  328        * Get the classpath used when looking up a resource.
  329        * @return the classpath
  330        * @since Ant 1.5
  331        */
  332       public Path getClasspath() {
  333           return classpath;
  334       }
  335   
  336       /**
  337        * @param userProperty ignored
  338        * @deprecated since 1.5.x.
  339        *             This was never a supported feature and has been
  340        *             deprecated without replacement.
  341        * @ant.attribute ignore="true"
  342        */
  343       public void setUserProperty(boolean userProperty) {
  344           log("DEPRECATED: Ignoring request to set user property in Property"
  345               + " task.", Project.MSG_WARN);
  346       }
  347   
  348       /**
  349        * get the value of this property
  350        * @return the current value or the empty string
  351        */
  352       public String toString() {
  353           return value == null ? "" : value;
  354       }
  355   
  356       /**
  357        * set the property in the project to the value.
  358        * if the task was give a file, resource or env attribute
  359        * here is where it is loaded
  360        * @throws BuildException on error
  361        */
  362       public void execute() throws BuildException {
  363           if (getProject() == null) {
  364               throw new IllegalStateException("project has not been set");
  365           }
  366   
  367           if (name != null) {
  368               if (value == null && ref == null) {
  369                   throw new BuildException("You must specify value, location or "
  370                                            + "refid with the name attribute",
  371                                            getLocation());
  372               }
  373           } else {
  374               if (url == null && file == null && resource == null && env == null) {
  375                   throw new BuildException("You must specify url, file, resource or "
  376                                            + "environment when not using the "
  377                                            + "name attribute", getLocation());
  378               }
  379           }
  380   
  381           if (url == null && file == null && resource == null && prefix != null) {
  382               throw new BuildException("Prefix is only valid when loading from "
  383                                        + "a url, file or resource", getLocation());
  384           }
  385   
  386           if ((name != null) && (value != null)) {
  387               addProperty(name, value);
  388           }
  389   
  390           if (file != null) {
  391               loadFile(file);
  392           }
  393   
  394           if (url != null) {
  395               loadUrl(url);
  396           }
  397   
  398           if (resource != null) {
  399               loadResource(resource);
  400           }
  401   
  402           if (env != null) {
  403               loadEnvironment(env);
  404           }
  405   
  406           if ((name != null) && (ref != null)) {
  407               try {
  408                   addProperty(name,
  409                               ref.getReferencedObject(getProject()).toString());
  410               } catch (BuildException be) {
  411                   if (fallback != null) {
  412                       addProperty(name,
  413                                   ref.getReferencedObject(fallback).toString());
  414                   } else {
  415                       throw be;
  416                   }
  417               }
  418           }
  419       }
  420   
  421       /**
  422        * load properties from a url
  423        * @param url url to load from
  424        * @throws BuildException on error
  425        */
  426       protected void loadUrl(URL url) throws BuildException {
  427           Properties props = new Properties();
  428           log("Loading " + url, Project.MSG_VERBOSE);
  429           try {
  430               InputStream is = url.openStream();
  431               try {
  432                   props.load(is);
  433               } finally {
  434                   if (is != null) {
  435                       is.close();
  436                   }
  437               }
  438               addProperties(props);
  439           } catch (IOException ex) {
  440               throw new BuildException(ex, getLocation());
  441           }
  442       }
  443   
  444   
  445       /**
  446        * load properties from a file
  447        * @param file file to load
  448        * @throws BuildException on error
  449        */
  450       protected void loadFile(File file) throws BuildException {
  451           Properties props = new Properties();
  452           log("Loading " + file.getAbsolutePath(), Project.MSG_VERBOSE);
  453           try {
  454               if (file.exists()) {
  455                   FileInputStream  fis = null;
  456                   try {
  457                       fis = new FileInputStream(file);
  458                       props.load(fis);
  459                   } finally {
  460                       if (fis != null) {
  461                           fis.close();
  462                       }
  463                   }
  464                   addProperties(props);
  465               } else {
  466                   log("Unable to find property file: " + file.getAbsolutePath(),
  467                       Project.MSG_VERBOSE);
  468               }
  469           } catch (IOException ex) {
  470               throw new BuildException(ex, getLocation());
  471           }
  472       }
  473   
  474       /**
  475        * load properties from a resource in the current classpath
  476        * @param name name of resource to load
  477        */
  478       protected void loadResource(String name) {
  479           Properties props = new Properties();
  480           log("Resource Loading " + name, Project.MSG_VERBOSE);
  481           InputStream is = null;
  482           try {
  483               ClassLoader cL = null;
  484   
  485               if (classpath != null) {
  486                   cL = getProject().createClassLoader(classpath);
  487               } else {
  488                   cL = this.getClass().getClassLoader();
  489               }
  490   
  491               if (cL == null) {
  492                   is = ClassLoader.getSystemResourceAsStream(name);
  493               } else {
  494                   is = cL.getResourceAsStream(name);
  495               }
  496   
  497               if (is != null) {
  498                   props.load(is);
  499                   addProperties(props);
  500               } else {
  501                   log("Unable to find resource " + name, Project.MSG_WARN);
  502               }
  503           } catch (IOException ex) {
  504               throw new BuildException(ex, getLocation());
  505           } finally {
  506               if (is != null) {
  507                   try {
  508                       is.close();
  509                   } catch (IOException e) {
  510                       // ignore
  511                   }
  512               }
  513           }
  514   
  515       }
  516   
  517       /**
  518        * load the environment values
  519        * @param prefix prefix to place before them
  520        */
  521       protected void loadEnvironment(String prefix) {
  522           Properties props = new Properties();
  523           if (!prefix.endsWith(".")) {
  524               prefix += ".";
  525           }
  526           log("Loading Environment " + prefix, Project.MSG_VERBOSE);
  527           Vector osEnv = Execute.getProcEnvironment();
  528           for (Enumeration e = osEnv.elements(); e.hasMoreElements();) {
  529               String entry = (String) e.nextElement();
  530               int pos = entry.indexOf('=');
  531               if (pos == -1) {
  532                   log("Ignoring: " + entry, Project.MSG_WARN);
  533               } else {
  534                   props.put(prefix + entry.substring(0, pos),
  535                   entry.substring(pos + 1));
  536               }
  537           }
  538           addProperties(props);
  539       }
  540   
  541       /**
  542        * iterate through a set of properties,
  543        * resolve them then assign them
  544        * @param props the properties to iterate over
  545        */
  546       protected void addProperties(Properties props) {
  547           resolveAllProperties(props);
  548           Enumeration e = props.keys();
  549           while (e.hasMoreElements()) {
  550               String propertyName = (String) e.nextElement();
  551               String propertyValue = props.getProperty(propertyName);
  552   
  553               String v = getProject().replaceProperties(propertyValue);
  554   
  555               if (prefix != null) {
  556                   propertyName = prefix + propertyName;
  557               }
  558   
  559               addProperty(propertyName, v);
  560           }
  561       }
  562   
  563       /**
  564        * add a name value pair to the project property set
  565        * @param n name of property
  566        * @param v value to set
  567        */
  568       protected void addProperty(String n, String v) {
  569           if (userProperty) {
  570               if (getProject().getUserProperty(n) == null) {
  571                   getProject().setInheritedProperty(n, v);
  572               } else {
  573                   log("Override ignored for " + n, Project.MSG_VERBOSE);
  574               }
  575           } else {
  576               getProject().setNewProperty(n, v);
  577           }
  578       }
  579   
  580       /**
  581        * resolve properties inside a properties hashtable
  582        * @param props properties object to resolve
  583        */
  584       private void resolveAllProperties(Properties props) throws BuildException {
  585           for (Enumeration e = props.keys(); e.hasMoreElements();) {
  586               String propertyName = (String) e.nextElement();
  587               Stack referencesSeen = new Stack();
  588               resolve(props, propertyName, referencesSeen);
  589           }
  590       }
  591   
  592       /**
  593        * Recursively expand the named property using the project's
  594        * reference table and the given set of properties - fail if a
  595        * circular definition is detected.
  596        *
  597        * @param props properties object to resolve
  598        * @param name of the property to resolve
  599        * @param referencesSeen stack of all property names that have
  600        * been tried to expand before coming here.
  601        */
  602       private void resolve(Properties props, String name, Stack referencesSeen)
  603           throws BuildException {
  604           if (referencesSeen.contains(name)) {
  605               throw new BuildException("Property " + name + " was circularly "
  606                                        + "defined.");
  607           }
  608   
  609           String propertyValue = props.getProperty(name);
  610           Vector fragments = new Vector();
  611           Vector propertyRefs = new Vector();
  612           PropertyHelper.getPropertyHelper(
  613               this.getProject()).parsePropertyString(
  614                   propertyValue, fragments, propertyRefs);
  615   
  616           if (propertyRefs.size() != 0) {
  617               referencesSeen.push(name);
  618               StringBuffer sb = new StringBuffer();
  619               Enumeration i = fragments.elements();
  620               Enumeration j = propertyRefs.elements();
  621               while (i.hasMoreElements()) {
  622                   String fragment = (String) i.nextElement();
  623                   if (fragment == null) {
  624                       String propertyName = (String) j.nextElement();
  625                       fragment = getProject().getProperty(propertyName);
  626                       if (fragment == null) {
  627                           if (props.containsKey(propertyName)) {
  628                               resolve(props, propertyName, referencesSeen);
  629                               fragment = props.getProperty(propertyName);
  630                           } else {
  631                               fragment = "${" + propertyName + "}";
  632                           }
  633                       }
  634                   }
  635                   sb.append(fragment);
  636               }
  637               propertyValue = sb.toString();
  638               props.put(name, propertyValue);
  639               referencesSeen.pop();
  640           }
  641       }
  642   }

Save This Page
Home » apache-ant-1.7.1-src » org.apache.tools » ant » taskdefs » [javadoc | source]