Clover coverage report - Ant Coverage
Coverage timestamp: Tue Apr 8 2003 20:43:55 EST
file stats: LOC: 391   Methods: 7
NCLOC: 248   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
AntStructure.java 1.6% 1.3% 14.3% 1.8%
 1   
 /*
 2   
  * The Apache Software License, Version 1.1
 3   
  *
 4   
  * Copyright (c) 2000-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.FileOutputStream;
 59   
 import java.io.FileWriter;
 60   
 import java.io.IOException;
 61   
 import java.io.OutputStreamWriter;
 62   
 import java.io.PrintWriter;
 63   
 import java.io.UnsupportedEncodingException;
 64   
 import java.util.Enumeration;
 65   
 import java.util.Hashtable;
 66   
 import java.util.Vector;
 67   
 import org.apache.tools.ant.BuildException;
 68   
 import org.apache.tools.ant.IntrospectionHelper;
 69   
 import org.apache.tools.ant.Task;
 70   
 import org.apache.tools.ant.TaskContainer;
 71   
 import org.apache.tools.ant.types.EnumeratedAttribute;
 72   
 
 73   
 /**
 74   
  * Creates a partial DTD for Ant from the currently known tasks.
 75   
  *
 76   
  * @author Stefan Bodewig
 77   
  *
 78   
  * @version $Revision: 1.32 $
 79   
  *
 80   
  * @since Ant 1.1
 81   
  *
 82   
  * @ant.task category="xml"
 83   
  */
 84   
 public class AntStructure extends Task {
 85   
 
 86   
     private final String lSep = System.getProperty("line.separator");
 87   
 
 88   
     private final String BOOLEAN = "%boolean;";
 89   
     private final String TASKS = "%tasks;";
 90   
     private final String TYPES = "%types;";
 91   
 
 92   
     private Hashtable visited = new Hashtable();
 93   
 
 94   
     private File output;
 95   
 
 96   
     /**
 97   
      * The output file.
 98   
      */
 99  0
     public void setOutput(File output) {
 100  0
         this.output = output;
 101   
     }
 102   
 
 103   
     /**
 104   
      * Build the antstructure DTD.
 105   
      *
 106   
      * @exception BuildException if the DTD cannot be written.
 107   
      */
 108  1
     public void execute() throws BuildException {
 109   
 
 110  1
         if (output == null) {
 111  1
             throw new BuildException("output attribute is required", getLocation());
 112   
         }
 113   
 
 114  0
         PrintWriter out = null;
 115  0
         try {
 116  0
             try {
 117  0
                 out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(output), "UTF8"));
 118   
             } catch (UnsupportedEncodingException ue) {
 119   
                 /*
 120   
                  * Plain impossible with UTF8, see
 121   
                  * http://java.sun.com/products/jdk/1.2/docs/guide/internat/encoding.doc.html
 122   
                  *
 123   
                  * fallback to platform specific anyway.
 124   
                  */
 125  0
                 out = new PrintWriter(new FileWriter(output));
 126   
             }
 127   
 
 128  0
             printHead(out, getProject().getTaskDefinitions().keys(),
 129   
                       getProject().getDataTypeDefinitions().keys());
 130   
 
 131  0
             printTargetDecl(out);
 132   
 
 133  0
             Enumeration dataTypes = getProject().getDataTypeDefinitions().keys();
 134  0
             while (dataTypes.hasMoreElements()) {
 135  0
                 String typeName = (String) dataTypes.nextElement();
 136  0
                 printElementDecl(out, typeName,
 137   
                                  (Class) getProject().getDataTypeDefinitions().get(typeName));
 138   
             }
 139   
 
 140  0
             Enumeration tasks = getProject().getTaskDefinitions().keys();
 141  0
             while (tasks.hasMoreElements()) {
 142  0
                 String taskName = (String) tasks.nextElement();
 143  0
                 printElementDecl(out, taskName,
 144   
                                  (Class) getProject().getTaskDefinitions().get(taskName));
 145   
             }
 146   
 
 147   
         } catch (IOException ioe) {
 148  0
             throw new BuildException("Error writing "
 149   
                 + output.getAbsolutePath(), ioe, getLocation());
 150   
         } finally {
 151  0
             if (out != null) {
 152  0
                 out.close();
 153   
             }
 154  0
             visited.clear();
 155   
         }
 156   
     }
 157   
 
 158   
     /**
 159   
      * Prints the header of the generated output.
 160   
      *
 161   
      * <p>Basically this prints the XML declaration, defines some
 162   
      * entities and the project element.</p>
 163   
      */
 164  0
     private void printHead(PrintWriter out, Enumeration tasks,
 165   
                            Enumeration types) {
 166  0
         out.println("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
 167  0
         out.println("<!ENTITY % boolean \"(true|false|on|off|yes|no)\">");
 168  0
         out.print("<!ENTITY % tasks \"");
 169  0
         boolean first = true;
 170  0
         while (tasks.hasMoreElements()) {
 171  0
             String taskName = (String) tasks.nextElement();
 172  0
             if (!first) {
 173  0
                 out.print(" | ");
 174   
             } else {
 175  0
                 first = false;
 176   
             }
 177  0
             out.print(taskName);
 178   
         }
 179  0
         out.println("\">");
 180  0
         out.print("<!ENTITY % types \"");
 181  0
         first = true;
 182  0
         while (types.hasMoreElements()) {
 183  0
             String typeName = (String) types.nextElement();
 184  0
             if (!first) {
 185  0
                 out.print(" | ");
 186   
             } else {
 187  0
                 first = false;
 188   
             }
 189  0
             out.print(typeName);
 190   
         }
 191  0
         out.println("\">");
 192   
 
 193  0
         out.println("");
 194   
 
 195  0
         out.print("<!ELEMENT project (target | ");
 196  0
         out.print(TASKS);
 197  0
         out.print(" | ");
 198  0
         out.print(TYPES);
 199  0
         out.println(")*>");
 200  0
         out.println("<!ATTLIST project");
 201  0
         out.println("          name    CDATA #IMPLIED");
 202  0
         out.println("          default CDATA #IMPLIED");
 203  0
         out.println("          basedir CDATA #IMPLIED>");
 204  0
         out.println("");
 205   
     }
 206   
 
 207   
     /**
 208   
      * Prints the definition for the target element.
 209   
      */
 210  0
     private void printTargetDecl(PrintWriter out) {
 211  0
         out.print("<!ELEMENT target (");
 212  0
         out.print(TASKS);
 213  0
         out.print(" | ");
 214  0
         out.print(TYPES);
 215  0
         out.println(")*>");
 216  0
         out.println("");
 217   
 
 218  0
         out.println("<!ATTLIST target");
 219  0
         out.println("          id          ID    #IMPLIED");
 220  0
         out.println("          name        CDATA #REQUIRED");
 221  0
         out.println("          if          CDATA #IMPLIED");
 222  0
         out.println("          unless      CDATA #IMPLIED");
 223  0
         out.println("          depends     CDATA #IMPLIED");
 224  0
         out.println("          description CDATA #IMPLIED>");
 225  0
         out.println("");
 226   
     }
 227   
 
 228   
     /**
 229   
      * Print the definition for a given element.
 230   
      */
 231  0
     private void printElementDecl(PrintWriter out, String name, Class element)
 232   
         throws BuildException {
 233   
 
 234  0
         if (visited.containsKey(name)) {
 235  0
             return;
 236   
         }
 237  0
         visited.put(name, "");
 238   
 
 239  0
         IntrospectionHelper ih = null;
 240  0
         try {
 241  0
             ih = IntrospectionHelper.getHelper(element);
 242   
         } catch (Throwable t) {
 243   
             /*
 244   
              * XXX - failed to load the class properly.
 245   
              *
 246   
              * should we print a warning here?
 247   
              */
 248  0
             return;
 249   
         }
 250   
 
 251  0
         StringBuffer sb = new StringBuffer("<!ELEMENT ");
 252  0
         sb.append(name).append(" ");
 253   
 
 254  0
         if (org.apache.tools.ant.types.Reference.class.equals(element)) {
 255  0
             sb.append("EMPTY>").append(lSep);
 256  0
             sb.append("<!ATTLIST ").append(name);
 257  0
             sb.append(lSep).append("          id ID #IMPLIED");
 258  0
             sb.append(lSep).append("          refid IDREF #IMPLIED");
 259  0
             sb.append(">").append(lSep);
 260  0
             out.println(sb);
 261  0
             return;
 262   
         }
 263   
 
 264  0
         Vector v = new Vector();
 265  0
         if (ih.supportsCharacters()) {
 266  0
             v.addElement("#PCDATA");
 267   
         }
 268   
 
 269  0
         if (TaskContainer.class.isAssignableFrom(element)) {
 270  0
             v.addElement(TASKS);
 271   
         }
 272   
 
 273  0
         Enumeration enum = ih.getNestedElements();
 274  0
         while (enum.hasMoreElements()) {
 275  0
             v.addElement(enum.nextElement());
 276   
         }
 277   
 
 278  0
         if (v.isEmpty()) {
 279  0
             sb.append("EMPTY");
 280   
         } else {
 281  0
             sb.append("(");
 282  0
             final int count = v.size();
 283  0
             for (int i = 0; i < count; i++) {
 284  0
                 if (i != 0) {
 285  0
                     sb.append(" | ");
 286   
                 }
 287  0
                 sb.append(v.elementAt(i));
 288   
             }
 289  0
             sb.append(")");
 290  0
             if (count > 1 || !v.elementAt(0).equals("#PCDATA")) {
 291  0
                 sb.append("*");
 292   
             }
 293   
         }
 294  0
         sb.append(">");
 295  0
         out.println(sb);
 296   
 
 297  0
         sb = new StringBuffer("<!ATTLIST ");
 298  0
         sb.append(name);
 299  0
         sb.append(lSep).append("          id ID #IMPLIED");
 300   
 
 301  0
         enum = ih.getAttributes();
 302  0
         while (enum.hasMoreElements()) {
 303  0
             String attrName = (String) enum.nextElement();
 304  0
             if ("id".equals(attrName)) {
 305  0
               continue;
 306   
             }
 307   
 
 308  0
             sb.append(lSep).append("          ").append(attrName).append(" ");
 309  0
             Class type = ih.getAttributeType(attrName);
 310  0
             if (type.equals(java.lang.Boolean.class) ||
 311   
                 type.equals(java.lang.Boolean.TYPE)) {
 312  0
                 sb.append(BOOLEAN).append(" ");
 313  0
             } else if (org.apache.tools.ant.types.Reference.class.isAssignableFrom(type)) {
 314  0
                 sb.append("IDREF ");
 315  0
             } else if (org.apache.tools.ant.types.EnumeratedAttribute.class.isAssignableFrom(type)) {
 316  0
                 try {
 317  0
                     EnumeratedAttribute ea =
 318   
                         (EnumeratedAttribute) type.newInstance();
 319  0
                     String[] values = ea.getValues();
 320  0
                     if (values == null
 321   
                         || values.length == 0
 322   
                         || !areNmtokens(values)) {
 323  0
                         sb.append("CDATA ");
 324   
                     } else {
 325  0
                         sb.append("(");
 326  0
                         for (int i = 0; i < values.length; i++) {
 327  0
                             if (i != 0) {
 328  0
                                 sb.append(" | ");
 329   
                             }
 330  0
                             sb.append(values[i]);
 331   
                         }
 332  0
                         sb.append(") ");
 333   
                     }
 334   
                 } catch (InstantiationException ie) {
 335  0
                     sb.append("CDATA ");
 336   
                 } catch (IllegalAccessException ie) {
 337  0
                     sb.append("CDATA ");
 338   
                 }
 339   
             } else {
 340  0
                 sb.append("CDATA ");
 341   
             }
 342  0
             sb.append("#IMPLIED");
 343   
         }
 344  0
         sb.append(">").append(lSep);
 345  0
         out.println(sb);
 346   
 
 347  0
         final int count = v.size();
 348  0
         for (int i = 0; i < count; i++) {
 349  0
             String nestedName = (String) v.elementAt(i);
 350  0
             if (!"#PCDATA".equals(nestedName)
 351   
                  && !TASKS.equals(nestedName)
 352   
                  && !TYPES.equals(nestedName)) {
 353  0
                 printElementDecl(out, nestedName, ih.getElementType(nestedName));
 354   
             }
 355   
         }
 356   
     }
 357   
 
 358   
     /**
 359   
      * Does this String match the XML-NMTOKEN production?
 360   
      */
 361  0
     protected boolean isNmtoken(String s) {
 362  0
         final int length = s.length();
 363  0
         for (int i = 0; i < length; i++) {
 364  0
             char c = s.charAt(i);
 365   
             // XXX - we are ommitting CombiningChar and Extender here
 366  0
             if (!Character.isLetterOrDigit(c) &&
 367   
                 c != '.' && c != '-' &&
 368   
                 c != '_' && c != ':') {
 369  0
                 return false;
 370   
             }
 371   
         }
 372  0
         return true;
 373   
     }
 374   
 
 375   
     /**
 376   
      * Do the Strings all match the XML-NMTOKEN production?
 377   
      *
 378   
      * <p>Otherwise they are not suitable as an enumerated attribute,
 379   
      * for example.</p>
 380   
      */
 381  0
     protected boolean areNmtokens(String[] s) {
 382  0
         for (int i = 0; i < s.length; i++) {
 383  0
             if (!isNmtoken(s[i])) {
 384  0
                 return false;
 385   
             }
 386   
         }
 387  0
         return true;
 388   
     }
 389   
 
 390   
 }
 391