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.IOException;
   23   import java.util.Hashtable;
   24   import javax.xml.parsers.DocumentBuilderFactory;
   25   import javax.xml.parsers.DocumentBuilder;
   26   import javax.xml.parsers.ParserConfigurationException;
   27   import org.apache.tools.ant.BuildException;
   28   import org.apache.tools.ant.Project;
   29   import org.apache.tools.ant.types.Path;
   30   import org.apache.tools.ant.types.Resource;
   31   import org.apache.tools.ant.types.ResourceCollection;
   32   import org.apache.tools.ant.types.XMLCatalog;
   33   import org.apache.tools.ant.types.resources.FileResource;
   34   import org.apache.tools.ant.util.FileUtils;
   35   import org.w3c.dom.Document;
   36   import org.w3c.dom.Element;
   37   import org.w3c.dom.NamedNodeMap;
   38   import org.w3c.dom.Node;
   39   import org.w3c.dom.NodeList;
   40   import org.xml.sax.SAXException;
   41   import org.xml.sax.EntityResolver;
   42   
   43   /**
   44    * Loads property values from a valid XML file, generating the
   45    * property names from the file's element and attribute names.
   46    *
   47    * <p>Example:</p>
   48    * <pre>
   49    *   &lt;root-tag myattr="true"&gt;
   50    *     &lt;inner-tag someattr="val"&gt;Text&lt;/inner-tag&gt;
   51    *     &lt;a2&gt;&lt;a3&gt;&lt;a4&gt;false&lt;/a4&gt;&lt;/a3&gt;&lt;/a2&gt;
   52    *     &lt;x&gt;x1&lt;/x&gt;
   53    *     &lt;x&gt;x2&lt;/x&gt;
   54    *   &lt;/root-tag&gt;
   55    *</pre>
   56    *
   57    * <p>this generates the following properties:</p>
   58    *
   59    * <pre>
   60    *  root-tag(myattr)=true
   61    *  root-tag.inner-tag=Text
   62    *  root-tag.inner-tag(someattr)=val
   63    *  root-tag.a2.a3.a4=false
   64    *  root-tag.x=x1,x2
   65    * </pre>
   66    *
   67    * <p>The <i>collapseAttributes</i> property of this task can be set
   68    * to true (the default is false) which will instead result in the
   69    * following properties (note the difference in names of properties
   70    * corresponding to XML attributes):</p>
   71    *
   72    * <pre>
   73    *  root-tag.myattr=true
   74    *  root-tag.inner-tag=Text
   75    *  root-tag.inner-tag.someattr=val
   76    *  root-tag.a2.a3.a4=false
   77    *  root-tag.x=x1,x2
   78    * </pre>
   79    *
   80    * <p>Optionally, to more closely mirror the abilities of the Property
   81    * task, a selected set of attributes can be treated specially.  To
   82    * enable this behavior, the "semanticAttributes" property of this task
   83    * must be set to true (it defaults to false).  If this attribute is
   84    * specified, the following attributes take on special meaning
   85    * (setting this to true implicitly sets collapseAttributes to true as
   86    * well):</p>
   87    *
   88    * <ul>
   89    *  <li><b>value</b>: Identifies a text value for a property.</li>
   90    *  <li><b>location</b>: Identifies a file location for a property.</li>
   91    *  <li><b>id</b>: Sets an id for a property</li>
   92    *  <li><b>refid</b>: Sets a property to the value of another property
   93    *       based upon the provided id</li>
   94    *  <li><b>pathid</b>: Defines a path rather than a property with
   95    *       the given id.</li>
   96    * </ul>
   97    *
   98    * <p>For example, with keepRoot = false, the following properties file:</p>
   99    *
  100    * <pre>
  101    * &lt;root-tag&gt;
  102    *   &lt;build&gt;
  103    *   &lt;build folder="build"&gt;
  104    *     &lt;classes id="build.classes" location="${build.folder}/classes"/&gt;
  105    *     &lt;reference refid="build.classes"/&gt;
  106    *   &lt;/build&gt;
  107    *   &lt;compile&gt;
  108    *     &lt;classpath pathid="compile.classpath"&gt;
  109    *       &lt;pathelement location="${build.classes}"/&gt;
  110    *     &lt;/classpath&gt;
  111    *   &lt;/compile&gt;
  112    *   &lt;run-time&gt;
  113    *     &lt;jars&gt;*.jar&lt;/jars&gt;
  114    *     &lt;classpath pathid="run-time.classpath"&gt;
  115    *       &lt;path refid="compile.classpath"/&gt;
  116    *       &lt;pathelement path="${run-time.jars}"/&gt;
  117    *     &lt;/classpath&gt;
  118    *   &lt;/run-time&gt;
  119    * &lt;/root-tag&gt;
  120    * </pre>
  121    *
  122    * <p>is equivalent to the following entries in a build file:</p>
  123    *
  124    * <pre>
  125    * &lt;property name="build" location="build"/&gt;
  126    * &lt;property name="build.classes" location="${build.location}/classes"/&gt;
  127    * &lt;property name="build.reference" refid="build.classes"/&gt;
  128    *
  129    * &lt;property name="run-time.jars" value="*.jar/&gt;
  130    *
  131    * &lt;classpath id="compile.classpath"&gt;
  132    *   &lt;pathelement location="${build.classes}"/&gt;
  133    * &lt;/classpath&gt;
  134    *
  135    * &lt;classpath id="run-time.classpath"&gt;
  136    *   &lt;path refid="compile.classpath"/&gt;
  137    *   &lt;pathelement path="${run-time.jars}"/&gt;
  138    * &lt;/classpath&gt;
  139    * </pre>
  140    *
  141    * <p> This task <i>requires</i> the following attributes:</p>
  142    *
  143    * <ul>
  144    * <li><b>file</b>: The name of the file to load.</li>
  145    * </ul>
  146    *
  147    * <p>This task supports the following attributes:</p>
  148    *
  149    * <ul>
  150    * <li><b>prefix</b>: Optionally specify a prefix applied to
  151    *     all properties loaded.  Defaults to an empty string.</li>
  152    * <li><b>keepRoot</b>: Indicate whether the root xml element
  153    *     is kept as part of property name.  Defaults to true.</li>
  154    * <li><b>validate</b>: Indicate whether the xml file is validated.
  155    *     Defaults to false.</li>
  156    * <li><b>collapseAttributes</b>: Indicate whether attributes are
  157    *     stored in property names with parens or with period
  158    *     delimiters.  Defaults to false, meaning properties
  159    *     are stored with parens (i.e., foo(attr)).</li>
  160    * <li><b>semanticAttributes</b>: Indicate whether attributes
  161    *     named "location", "value", "refid" and "path"
  162    *     are interpreted as ant properties.  Defaults
  163    *     to false.</li>
  164    * <li><b>rootDirectory</b>: Indicate the directory to use
  165    *     as the root directory for resolving location
  166    *     properties.  Defaults to the directory
  167    *     of the project using the task.</li>
  168    * <li><b>includeSemanticAttribute</b>: Indicate whether to include
  169    *     the semantic attribute ("location" or "value") as
  170    *     part of the property name.  Defaults to false.</li>
  171    * </ul>
  172    *
  173    * @ant.task name="xmlproperty" category="xml"
  174    */
  175   
  176   public class XmlProperty extends org.apache.tools.ant.Task {
  177   
  178       private Resource src;
  179       private String prefix = "";
  180       private boolean keepRoot = true;
  181       private boolean validate = false;
  182       private boolean collapseAttributes = false;
  183       private boolean semanticAttributes = false;
  184       private boolean includeSemanticAttribute = false;
  185       private File rootDirectory = null;
  186       private Hashtable addedAttributes = new Hashtable();
  187       private XMLCatalog xmlCatalog = new XMLCatalog();
  188       private String delimiter = ",";
  189   
  190       private static final String ID = "id";
  191       private static final String REF_ID = "refid";
  192       private static final String LOCATION = "location";
  193       private static final String VALUE = "value";
  194       private static final String PATH = "path";
  195       private static final String PATHID = "pathid";
  196       private static final String[] ATTRIBUTES = new String[] {
  197           ID, REF_ID, LOCATION, VALUE, PATH, PATHID
  198       };
  199       private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
  200   
  201       /**
  202        * Constructor.
  203        */
  204       public XmlProperty() {
  205           super();
  206       }
  207   
  208       /**
  209        * Initializes the task.
  210        */
  211   
  212       public void init() {
  213           super.init();
  214           xmlCatalog.setProject(getProject());
  215       }
  216   
  217   
  218       /**
  219        * @return the xmlCatalog as the entityresolver.
  220        */
  221       protected EntityResolver getEntityResolver() {
  222           return xmlCatalog;
  223       }
  224   
  225       /**
  226        * Run the task.
  227        * @throws BuildException The exception raised during task execution.
  228        * @todo validate the source file is valid before opening, print a better error message
  229        * @todo add a verbose level log message listing the name of the file being loaded
  230        */
  231       public void execute()
  232               throws BuildException {
  233   
  234           Resource r = getResource();
  235   
  236           if (r == null) {
  237               String msg = "XmlProperty task requires a source resource";
  238               throw new BuildException(msg);
  239           }
  240   
  241           try {
  242               log("Loading " + src, Project.MSG_VERBOSE);
  243   
  244               if (r.isExists()) {
  245   
  246                 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  247                 factory.setValidating(validate);
  248                 factory.setNamespaceAware(false);
  249                 DocumentBuilder builder = factory.newDocumentBuilder();
  250                 builder.setEntityResolver(getEntityResolver());
  251                 Document document = null;
  252                 if (src instanceof FileResource) {
  253                     document = builder.parse(((FileResource) src).getFile());
  254                 } else {
  255                     document = builder.parse(src.getInputStream());
  256                 }
  257                 Element topElement = document.getDocumentElement();
  258   
  259                 // Keep a hashtable of attributes added by this task.
  260                 // This task is allow to override its own properties
  261                 // but not other properties.  So we need to keep track
  262                 // of which properties we've added.
  263                 addedAttributes = new Hashtable();
  264   
  265                 if (keepRoot) {
  266                     addNodeRecursively(topElement, prefix, null);
  267                 } else {
  268                     NodeList topChildren = topElement.getChildNodes();
  269                     int numChildren = topChildren.getLength();
  270                     for (int i = 0; i < numChildren; i++) {
  271                       addNodeRecursively(topChildren.item(i), prefix, null);
  272                     }
  273                 }
  274   
  275               } else {
  276                   log("Unable to find property resource: " + r,
  277                       Project.MSG_VERBOSE);
  278               }
  279   
  280           } catch (SAXException sxe) {
  281               // Error generated during parsing
  282               Exception x = sxe;
  283               if (sxe.getException() != null) {
  284                   x = sxe.getException();
  285               }
  286               throw new BuildException("Failed to load " + src, x);
  287   
  288           } catch (ParserConfigurationException pce) {
  289               // Parser with specified options can't be built
  290               throw new BuildException(pce);
  291           } catch (IOException ioe) {
  292               // I/O error
  293               throw new BuildException("Failed to load " + src, ioe);
  294           }
  295       }
  296   
  297       /** Iterate through all nodes in the tree. */
  298       private void addNodeRecursively(Node node, String prefix,
  299                                       Object container) {
  300   
  301           // Set the prefix for this node to include its tag name.
  302           String nodePrefix = prefix;
  303           if (node.getNodeType() != Node.TEXT_NODE) {
  304               if (prefix.trim().length() > 0) {
  305                   nodePrefix += ".";
  306               }
  307               nodePrefix += node.getNodeName();
  308           }
  309   
  310           // Pass the container to the processing of this node,
  311           Object nodeObject = processNode(node, nodePrefix, container);
  312   
  313           // now, iterate through children.
  314           if (node.hasChildNodes()) {
  315   
  316               NodeList nodeChildren = node.getChildNodes();
  317               int numChildren = nodeChildren.getLength();
  318   
  319               for (int i = 0; i < numChildren; i++) {
  320                   // For each child, pass the object added by
  321                   // processNode to its children -- in other word, each
  322                   // object can pass information along to its children.
  323                   addNodeRecursively(nodeChildren.item(i), nodePrefix,
  324                                      nodeObject);
  325               }
  326           }
  327       }
  328   
  329       void addNodeRecursively(org.w3c.dom.Node node, String prefix) {
  330           addNodeRecursively(node, prefix, null);
  331       }
  332   
  333       /**
  334        * Process the given node, adding any required attributes from
  335        * this child node alone -- but <em>not</em> processing any
  336        * children.
  337        *
  338        * @param node the XML Node to parse
  339        * @param prefix A string to prepend to any properties that get
  340        * added by this node.
  341        * @param container Optionally, an object that a parent node
  342        * generated that this node might belong to.  For example, this
  343        * node could be within a node that generated a Path.
  344        * @return the Object created by this node.  Generally, this is
  345        * either a String if this node resulted in setting an attribute,
  346        * or a Path.
  347        */
  348       public Object processNode (Node node, String prefix, Object container) {
  349   
  350           // Parse the attribute(s) and text of this node, adding
  351           // properties for each.
  352           // if the "path" attribute is specified, then return the created path
  353           // which will be passed to the children of this node.
  354           Object addedPath = null;
  355   
  356           // The value of an id attribute of this node.
  357           String id = null;
  358   
  359           if (node.hasAttributes()) {
  360   
  361               NamedNodeMap nodeAttributes = node.getAttributes();
  362   
  363               // Is there an id attribute?
  364               Node idNode = nodeAttributes.getNamedItem(ID);
  365               id = (semanticAttributes && idNode != null
  366                     ? idNode.getNodeValue() : null);
  367   
  368               // Now, iterate through the attributes adding them.
  369               for (int i = 0; i < nodeAttributes.getLength(); i++) {
  370   
  371                   Node attributeNode = nodeAttributes.item(i);
  372   
  373                   if (!semanticAttributes) {
  374                       String attributeName = getAttributeName(attributeNode);
  375                       String attributeValue = getAttributeValue(attributeNode);
  376                       addProperty(prefix + attributeName, attributeValue, null);
  377                   } else {
  378   
  379                       String nodeName = attributeNode.getNodeName();
  380                       String attributeValue = getAttributeValue(attributeNode);
  381   
  382                       Path containingPath = (container != null
  383                           && container instanceof Path ? (Path) container : null);
  384   
  385                       /*
  386                        * The main conditional logic -- if the attribute
  387                        * is somehow "special" (i.e., it has known
  388                        * semantic meaning) then deal with it
  389                        * appropriately.
  390                        */
  391                       if (nodeName.equals(ID)) {
  392                           // ID has already been found above.
  393                           continue;
  394                       } else if (containingPath != null
  395                                  && nodeName.equals(PATH)) {
  396                           // A "path" attribute for a node within a Path object.
  397                           containingPath.setPath(attributeValue);
  398                       } else if (container instanceof Path
  399                                  && nodeName.equals(REF_ID)) {
  400                           // A "refid" attribute for a node within a Path object.
  401                           containingPath.setPath(attributeValue);
  402                       } else if (container instanceof Path
  403                                  && nodeName.equals(LOCATION)) {
  404                           // A "location" attribute for a node within a
  405                           // Path object.
  406                           containingPath.setLocation(resolveFile(attributeValue));
  407                       } else if (nodeName.equals(PATHID)) {
  408                           // A node identifying a new path
  409                           if (container != null) {
  410                               throw new BuildException("XmlProperty does not "
  411                                                        + "support nested paths");
  412                           }
  413   
  414                           addedPath = new Path(getProject());
  415                           getProject().addReference(attributeValue, addedPath);
  416                       } else {
  417                           // An arbitrary attribute.
  418                           String attributeName = getAttributeName(attributeNode);
  419                           addProperty(prefix + attributeName, attributeValue, id);
  420                       }
  421                   }
  422               }
  423           }
  424   
  425           String nodeText = null;
  426           boolean emptyNode = false;
  427           boolean semanticEmptyOverride = false;
  428           if (node.getNodeType() == Node.ELEMENT_NODE
  429               && semanticAttributes
  430               && node.hasAttributes()
  431               && (node.getAttributes().getNamedItem(VALUE) != null
  432                   || node.getAttributes().getNamedItem(LOCATION) != null
  433                   || node.getAttributes().getNamedItem(REF_ID) != null
  434                   || node.getAttributes().getNamedItem(PATH) != null
  435                   || node.getAttributes().getNamedItem(PATHID) != null)) {
  436               semanticEmptyOverride = true;
  437           }
  438           if (node.getNodeType() == Node.TEXT_NODE) {
  439               // For the text node, add a property.
  440               nodeText = getAttributeValue(node);
  441           } else if ((node.getNodeType() == Node.ELEMENT_NODE)
  442               && (node.getChildNodes().getLength() == 1)
  443               && (node.getFirstChild().getNodeType() == Node.CDATA_SECTION_NODE)) {
  444   
  445               nodeText = node.getFirstChild().getNodeValue();
  446               if ("".equals(nodeText) && !semanticEmptyOverride) {
  447                   emptyNode = true;
  448               }
  449           } else if ((node.getNodeType() == Node.ELEMENT_NODE)
  450                      && (node.getChildNodes().getLength() == 0)
  451                      && !semanticEmptyOverride) {
  452               nodeText = "";
  453               emptyNode = true;
  454           } else if ((node.getNodeType() == Node.ELEMENT_NODE)
  455                      && (node.getChildNodes().getLength() == 1)
  456                      && (node.getFirstChild().getNodeType() == Node.TEXT_NODE)
  457                      && ("".equals(node.getFirstChild().getNodeValue()))
  458                      && !semanticEmptyOverride) {
  459               nodeText = "";
  460               emptyNode = true;
  461           }
  462   
  463           if (nodeText != null) {
  464               // If the containing object was a String, then use it as the ID.
  465               if (semanticAttributes && id == null
  466                   && container instanceof String) {
  467                   id = (String) container;
  468               }
  469               if (nodeText.trim().length() != 0 || emptyNode) {
  470                   addProperty(prefix, nodeText, id);
  471               }
  472           }
  473   
  474           // Return the Path we added or the ID of this node for
  475           // children to reference if needed.  Path objects are
  476           // definitely used by child path elements, and ID may be used
  477           // for a child text node.
  478           return (addedPath != null ? addedPath : id);
  479       }
  480   
  481       /**
  482        * Actually add the given property/value to the project
  483        * after writing a log message.
  484        */
  485       private void addProperty (String name, String value, String id) {
  486           String msg = name + ":" + value;
  487           if (id != null) {
  488               msg += ("(id=" + id + ")");
  489           }
  490           log(msg, Project.MSG_DEBUG);
  491   
  492           if (addedAttributes.containsKey(name)) {
  493               // If this attribute was added by this task, then
  494               // we append this value to the existing value.
  495               // We use the setProperty method which will
  496               // forcibly override the property if it already exists.
  497               // We need to put these properties into the project
  498               // when we read them, though (instead of keeping them
  499               // outside of the project and batch adding them at the end)
  500               // to allow other properties to reference them.
  501               value = (String) addedAttributes.get(name) + getDelimiter() + value;
  502               getProject().setProperty(name, value);
  503               addedAttributes.put(name, value);
  504           } else if (getProject().getProperty(name) == null) {
  505               getProject().setNewProperty(name, value);
  506               addedAttributes.put(name, value);
  507           } else {
  508               log("Override ignored for property " + name, Project.MSG_VERBOSE);
  509           }
  510           if (id != null) {
  511               getProject().addReference(id, value);
  512           }
  513       }
  514   
  515       /**
  516        * Return a reasonable attribute name for the given node.
  517        * If we are using semantic attributes or collapsing
  518        * attributes, the returned name is ".nodename".
  519        * Otherwise, we return "(nodename)".  This is long-standing
  520        * (and default) &lt;xmlproperty&gt; behavior.
  521        */
  522       private String getAttributeName (Node attributeNode) {
  523           String attributeName = attributeNode.getNodeName();
  524   
  525           if (semanticAttributes) {
  526               // Never include the "refid" attribute as part of the
  527               // attribute name.
  528               if (attributeName.equals(REF_ID)) {
  529                   return "";
  530               // Otherwise, return it appended unless property to hide it is set.
  531               } else if (!isSemanticAttribute(attributeName)
  532                          || includeSemanticAttribute) {
  533                   return "." + attributeName;
  534               } else {
  535                   return "";
  536               }
  537           } else if (collapseAttributes) {
  538               return "." + attributeName;
  539           } else {
  540               return "(" + attributeName + ")";
  541           }
  542       }
  543   
  544       /**
  545        * Return whether the provided attribute name is recognized or not.
  546        */
  547       private static boolean isSemanticAttribute (String attributeName) {
  548           for (int i = 0; i < ATTRIBUTES.length; i++) {
  549               if (attributeName.equals(ATTRIBUTES[i])) {
  550                   return true;
  551               }
  552           }
  553           return false;
  554       }
  555   
  556       /**
  557        * Return the value for the given attribute.
  558        * If we are not using semantic attributes, its just the
  559        * literal string value of the attribute.
  560        *
  561        * <p>If we <em>are</em> using semantic attributes, then first
  562        * dependent properties are resolved (i.e., ${foo} is resolved
  563        * based on the foo property value), and then an appropriate data
  564        * type is used.  In particular, location-based properties are
  565        * resolved to absolute file names.  Also for refid values, look
  566        * up the referenced object from the project.</p>
  567        */
  568       private String getAttributeValue (Node attributeNode) {
  569           String nodeValue = attributeNode.getNodeValue().trim();
  570           if (semanticAttributes) {
  571               String attributeName = attributeNode.getNodeName();
  572               nodeValue = getProject().replaceProperties(nodeValue);
  573               if (attributeName.equals(LOCATION)) {
  574                   File f = resolveFile(nodeValue);
  575                   return f.getPath();
  576               } else if (attributeName.equals(REF_ID)) {
  577                   Object ref = getProject().getReference(nodeValue);
  578                   if (ref != null) {
  579                       return ref.toString();
  580                   }
  581               }
  582           }
  583           return nodeValue;
  584       }
  585   
  586       /**
  587        * The XML file to parse; required.
  588        * @param src the file to parse
  589        */
  590       public void setFile(File src) {
  591           setSrcResource(new FileResource(src));
  592       }
  593   
  594       /**
  595        * The resource to pack; required.
  596        * @param src resource to expand
  597        */
  598       public void setSrcResource(Resource src) {
  599           if (src.isDirectory()) {
  600               throw new BuildException("the source can't be a directory");
  601           }
  602           if (src instanceof FileResource && !supportsNonFileResources()) {
  603               throw new BuildException("Only FileSystem resources are"
  604                                        + " supported.");
  605           }
  606           this.src = src;
  607       }
  608   
  609       /**
  610        * Set the source resource.
  611        * @param a the resource to pack as a single element Resource collection.
  612        */
  613       public void addConfigured(ResourceCollection a) {
  614           if (a.size() != 1) {
  615               throw new BuildException("only single argument resource collections"
  616                                        + " are supported as archives");
  617           }
  618           setSrcResource((Resource) a.iterator().next());
  619       }
  620   
  621       /**
  622        * the prefix to prepend to each property
  623        * @param prefix the prefix to prepend to each property
  624        */
  625       public void setPrefix(String prefix) {
  626           this.prefix = prefix.trim();
  627       }
  628   
  629       /**
  630        * flag to include the xml root tag as a
  631        * first value in the property name; optional,
  632        * default is true
  633        * @param keepRoot if true (default), include the xml root tag
  634        */
  635       public void setKeeproot(boolean keepRoot) {
  636           this.keepRoot = keepRoot;
  637       }
  638   
  639       /**
  640        * flag to validate the XML file; optional, default false
  641        * @param validate if true validate the XML file, default false
  642        */
  643       public void setValidate(boolean validate) {
  644           this.validate = validate;
  645       }
  646   
  647       /**
  648        * flag to treat attributes as nested elements;
  649        * optional, default false
  650        * @param collapseAttributes if true treat attributes as nested elements
  651        */
  652       public void setCollapseAttributes(boolean collapseAttributes) {
  653           this.collapseAttributes = collapseAttributes;
  654       }
  655   
  656       /**
  657        * Attribute to enable special handling of attributes - see ant manual.
  658        * @param semanticAttributes if true enable the special handling.
  659        */
  660       public void setSemanticAttributes(boolean semanticAttributes) {
  661           this.semanticAttributes = semanticAttributes;
  662       }
  663   
  664       /**
  665        * The directory to use for resolving file references.
  666        * Ignored if semanticAttributes is not set to true.
  667        * @param rootDirectory the directory.
  668        */
  669       public void setRootDirectory(File rootDirectory) {
  670           this.rootDirectory = rootDirectory;
  671       }
  672   
  673       /**
  674        * Include the semantic attribute name as part of the property name.
  675        * Ignored if semanticAttributes is not set to true.
  676        * @param includeSemanticAttribute if true include the sematic attribute
  677        *                                 name.
  678        */
  679       public void setIncludeSemanticAttribute(boolean includeSemanticAttribute) {
  680           this.includeSemanticAttribute = includeSemanticAttribute;
  681       }
  682   
  683       /**
  684        * add an XMLCatalog as a nested element; optional.
  685        * @param catalog the XMLCatalog to use
  686        */
  687       public void addConfiguredXMLCatalog(XMLCatalog catalog) {
  688           xmlCatalog.addConfiguredXMLCatalog(catalog);
  689       }
  690   
  691       /* Expose members for extensibility */
  692   
  693       /**
  694        * @return the file attribute.
  695        */
  696       protected File getFile () {
  697           if (src instanceof FileResource) {
  698               return ((FileResource) src).getFile();
  699           } else {
  700               return null;
  701           }
  702       }
  703   
  704       /**
  705        * @return the resource.
  706        */
  707       protected Resource getResource() {
  708           // delegate this way around to support subclasses that
  709           // overwrite getFile
  710           File f = getFile();
  711           if (f != null) {
  712               return new FileResource(f);
  713           } else {
  714               return src;
  715           }
  716       }
  717   
  718       /**
  719        * @return the prefix attribute.
  720        */
  721       protected String getPrefix () {
  722           return this.prefix;
  723       }
  724   
  725       /**
  726        * @return the keeproot attribute.
  727        */
  728       protected boolean getKeeproot () {
  729           return this.keepRoot;
  730       }
  731   
  732       /**
  733        * @return the validate attribute.
  734        */
  735       protected boolean getValidate () {
  736           return this.validate;
  737       }
  738   
  739       /**
  740        * @return the collapse attributes attribute.
  741        */
  742       protected boolean getCollapseAttributes () {
  743           return this.collapseAttributes;
  744       }
  745   
  746       /**
  747        * @return the semantic attributes attribute.
  748        */
  749       protected boolean getSemanticAttributes () {
  750           return this.semanticAttributes;
  751       }
  752   
  753       /**
  754        * @return the root directory attribute.
  755        */
  756       protected File getRootDirectory () {
  757           return this.rootDirectory;
  758       }
  759   
  760       /**
  761        * @return the include semantic attribute.
  762        */
  763       protected boolean getIncludeSementicAttribute () {
  764           return this.includeSemanticAttribute;
  765       }
  766   
  767       /**
  768        * Let project resolve the file - or do it ourselves if
  769        * rootDirectory has been set.
  770        */
  771       private File resolveFile(String fileName) {
  772           if (rootDirectory == null) {
  773               return FILE_UTILS.resolveFile(getProject().getBaseDir(), fileName);
  774           }
  775           return FILE_UTILS.resolveFile(rootDirectory, fileName);
  776       }
  777   
  778       /**
  779        * Whether this task can deal with non-file resources.
  780        *
  781        * <p>This implementation returns true only if this task is
  782        * &lt;xmlproperty&gt;.  Any subclass of this class that also wants to
  783        * support non-file resources needs to override this method.  We
  784        * need to do so for backwards compatibility reasons since we
  785        * can't expect subclasses to support resources.</p>
  786        * @return true for this task.
  787        * @since Ant 1.7
  788        */
  789       protected boolean supportsNonFileResources() {
  790           return getClass().equals(XmlProperty.class);
  791       }
  792   
  793       public String getDelimiter() {
  794           return delimiter;
  795       }
  796   
  797       public void setDelimiter(String delimiter) {
  798           this.delimiter = delimiter;
  799       }
  800   }

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