You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ant.apache.org by bo...@apache.org on 2005/09/28 20:34:11 UTC

svn commit: r292244 - in /ant/core/trunk: docs/manual/CoreTasks/antstructure.html src/etc/testcases/taskdefs/antstructure.xml src/main/org/apache/tools/ant/taskdefs/AntStructure.java src/testcases/org/apache/tools/ant/taskdefs/AntStructureTest.java

Author: bodewig
Date: Wed Sep 28 11:34:04 2005
New Revision: 292244

URL: http://svn.apache.org/viewcvs?rev=292244&view=rev
Log:
lay grounds for Schema or Relax NG description generators as plugins in antstructure

Modified:
    ant/core/trunk/docs/manual/CoreTasks/antstructure.html
    ant/core/trunk/src/etc/testcases/taskdefs/antstructure.xml
    ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/AntStructure.java
    ant/core/trunk/src/testcases/org/apache/tools/ant/taskdefs/AntStructureTest.java

Modified: ant/core/trunk/docs/manual/CoreTasks/antstructure.html
URL: http://svn.apache.org/viewcvs/ant/core/trunk/docs/manual/CoreTasks/antstructure.html?rev=292244&r1=292243&r2=292244&view=diff
==============================================================================
--- ant/core/trunk/docs/manual/CoreTasks/antstructure.html (original)
+++ ant/core/trunk/docs/manual/CoreTasks/antstructure.html Wed Sep 28 11:34:04 2005
@@ -30,6 +30,14 @@
 target="_top">here</a> for a way to get around this problem.</p>
 <p>This task doesn't know about required attributes, all will be
 listed as <code>#IMPLIED</code>.</p>
+
+<p><em>Since Ant 1.7</em> custom structure printers can be used
+instead of the one that emits a DTD.  In order to plug in your own
+structure, you have to implement the interface
+<code>org.apache.tools.ant.taskdefs.AntStructure.StructurePrinter</code>
+and <code>&lt;typedef&gt; your class and use the new type as a nested
+element of this task - see the example below.</code>
+
 <h3>Parameters</h3>
 <table border="1" cellpadding="2" cellspacing="0">
   <tr>
@@ -47,6 +55,31 @@
 <blockquote><pre>
 &lt;antstructure output=&quot;project.dtd&quot;/&gt;
 </pre></blockquote>
+
+<p><b>Emitting your own structure instead of a DTD</b></p>
+
+<p>First you need to implement the interface</p>
+
+<pre>
+package org.example;
+import org.apache.tools.ant.taskdefs.AntStructure;
+public class MyPrinter implements AntStructure.StructurePrinter {
+    ...
+}
+</pre>
+
+<p>and then use it via typedef</p>
+
+<pre>
+  &lt;typedef name="myprinter" classname="org.example.MyPrinter"/&gt;
+  &lt;antstructure output="project.my"&gt;
+    &lt;myprinter/&gt;
+  &lt;antstructure&gt;
+</pre>
+
+<p>Your own StructurePrinter can accept attributes and nested elements
+just like any other Ant type or task.</p>
+
 <hr><p align="center">Copyright &copy; 2000-2002,2004-2005 The Apache Software Foundation. All rights
 Reserved.</p>
 

Modified: ant/core/trunk/src/etc/testcases/taskdefs/antstructure.xml
URL: http://svn.apache.org/viewcvs/ant/core/trunk/src/etc/testcases/taskdefs/antstructure.xml?rev=292244&r1=292243&r2=292244&view=diff
==============================================================================
--- ant/core/trunk/src/etc/testcases/taskdefs/antstructure.xml (original)
+++ ant/core/trunk/src/etc/testcases/taskdefs/antstructure.xml Wed Sep 28 11:34:04 2005
@@ -6,4 +6,20 @@
     <antstructure/>
   </target>
 
+  <target name="testCustomPrinter">
+    <typedef name="myprinter"
+             classname="org.apache.tools.ant.taskdefs.AntStructureTest$MyPrinter">
+      <classpath>
+        <pathelement path="${tests-classpath.value}"/>
+      </classpath>
+    </typedef>
+    <antstructure output="foo.dtd">
+      <myprinter/>
+    </antstructure>
+  </target>
+
+  <target name="tearDown">
+    <delete file="foo.dtd" quiet="true"/>
+  </target>
+
 </project>

Modified: ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/AntStructure.java
URL: http://svn.apache.org/viewcvs/ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/AntStructure.java?rev=292244&r1=292243&r2=292244&view=diff
==============================================================================
--- ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/AntStructure.java (original)
+++ ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/AntStructure.java Wed Sep 28 11:34:04 2005
@@ -29,6 +29,7 @@
 import java.util.Vector;
 import org.apache.tools.ant.BuildException;
 import org.apache.tools.ant.IntrospectionHelper;
+import org.apache.tools.ant.Project;
 import org.apache.tools.ant.Task;
 import org.apache.tools.ant.TaskContainer;
 import org.apache.tools.ant.types.EnumeratedAttribute;
@@ -44,15 +45,10 @@
  */
 public class AntStructure extends Task {
 
-    private final String lSep = System.getProperty("line.separator");
-
-    private static final String BOOLEAN = "%boolean;";
-    private static final String TASKS = "%tasks;";
-    private static final String TYPES = "%types;";
-
-    private Hashtable visited = new Hashtable();
+    private static final String lSep = System.getProperty("line.separator");
 
     private File output;
+    private StructurePrinter printer = new DTDPrinter();
 
     /**
      * The output file.
@@ -63,6 +59,14 @@
     }
 
     /**
+     * The StructurePrinter to use.
+     * @since Ant 1.7
+     */
+    public void add(StructurePrinter p) {
+	printer = p;
+    }
+
+    /**
      * Build the antstructure DTD.
      *
      * @exception BuildException if the DTD cannot be written.
@@ -87,25 +91,28 @@
                 out = new PrintWriter(new FileWriter(output));
             }
 
-            printHead(out, getProject().getTaskDefinitions().keys(),
-                      getProject().getDataTypeDefinitions().keys());
+            printer.printHead(out, getProject(),
+			      getProject().getTaskDefinitions(),
+			      getProject().getDataTypeDefinitions());
 
-            printTargetDecl(out);
+            printer.printTargetDecl(out);
 
             Enumeration dataTypes = getProject().getDataTypeDefinitions().keys();
             while (dataTypes.hasMoreElements()) {
                 String typeName = (String) dataTypes.nextElement();
-                printElementDecl(out, typeName,
+                printer.printElementDecl(out, getProject(), typeName,
                                  (Class) getProject().getDataTypeDefinitions().get(typeName));
             }
 
             Enumeration tasks = getProject().getTaskDefinitions().keys();
             while (tasks.hasMoreElements()) {
                 String tName = (String) tasks.nextElement();
-                printElementDecl(out, tName,
+                printer.printElementDecl(out, getProject(), tName,
                                  (Class) getProject().getTaskDefinitions().get(tName));
             }
 
+	    printer.printTail(out);
+
         } catch (IOException ioe) {
             throw new BuildException("Error writing "
                 + output.getAbsolutePath(), ioe, getLocation());
@@ -113,11 +120,73 @@
             if (out != null) {
                 out.close();
             }
-            visited.clear();
         }
     }
 
     /**
+     * Writes the actual structure information.
+     *
+     * <p>{@link StructurePrinter#printHead printHead}, {@link
+     * StructurePrinter#printTargetDecl printTargetDecl} and {@link
+     * StructurePrinter#printTail printTail} are called exactly once,
+     * {@link StructurePrinter#printElement printElement} once for
+     * each declared task and type.</p>
+     */
+    public static interface StructurePrinter {
+	/**
+	 * Prints the header of the generated output.
+	 *
+	 * @param out PrintWriter to write to.
+	 * @param p Project instance for the current task
+	 * @param tasks map (name to implementing class)
+	 * @param types map (name to implementing class)
+	 * data types.
+	 */
+	void printHead(PrintWriter out, Project p, Hashtable tasks,
+		       Hashtable types);
+
+	/**
+	 * Prints the definition for the target element.
+	 * @param out PrintWriter to write to.
+	 */
+	void printTargetDecl(PrintWriter out);
+
+	/**
+	 * Print the definition for a given element.
+	 *
+	 * @param out PrintWriter to write to.
+	 * @param p Project instance for the current task
+	 * @param name element name.
+	 * @param name class of the defined element.
+	 */
+	void printElementDecl(PrintWriter out, Project p, String name,
+			      Class element);
+
+	/**
+	 * Prints the trailer.
+	 * @param out PrintWriter to write to.
+	 */
+	void printTail(PrintWriter out);
+    }
+
+    private static class DTDPrinter implements StructurePrinter {
+
+	private static final String BOOLEAN = "%boolean;";
+	private static final String TASKS = "%tasks;";
+	private static final String TYPES = "%types;";
+
+	private Hashtable visited = new Hashtable();
+
+	public void printTail(PrintWriter out) {
+	    visited.clear();
+	}
+
+	public void printHead(PrintWriter out, Project p, Hashtable tasks, Hashtable types) {
+	    printHead(out, tasks.keys(), types.keys());
+	}
+
+
+    /**
      * Prints the header of the generated output.
      *
      * <p>Basically this prints the XML declaration, defines some
@@ -169,7 +238,7 @@
     /**
      * Prints the definition for the target element.
      */
-    private void printTargetDecl(PrintWriter out) {
+    public void printTargetDecl(PrintWriter out) {
         out.print("<!ELEMENT target (");
         out.print(TASKS);
         out.print(" | ");
@@ -190,8 +259,8 @@
     /**
      * Print the definition for a given element.
      */
-    private void printElementDecl(PrintWriter out, String name, Class element)
-        throws BuildException {
+	public void printElementDecl(PrintWriter out, Project p,
+				     String name, Class element) {
 
         if (visited.containsKey(name)) {
             return;
@@ -200,7 +269,7 @@
 
         IntrospectionHelper ih = null;
         try {
-            ih = IntrospectionHelper.getHelper(getProject(), element);
+            ih = IntrospectionHelper.getHelper(p, element);
         } catch (Throwable t) {
             /*
              * XXX - failed to load the class properly.
@@ -312,7 +381,7 @@
             if (!"#PCDATA".equals(nestedName)
                  && !TASKS.equals(nestedName)
                  && !TYPES.equals(nestedName)) {
-                printElementDecl(out, nestedName, ih.getElementType(nestedName));
+                printElementDecl(out, p, nestedName, ih.getElementType(nestedName));
             }
         }
     }
@@ -322,7 +391,7 @@
      * @param s the string to test
      * @return true if the string matches the XML-NMTOKEN
      */
-    protected boolean isNmtoken(String s) {
+    public static final boolean isNmtoken(String s) {
         final int length = s.length();
         for (int i = 0; i < length; i++) {
             char c = s.charAt(i);
@@ -343,7 +412,7 @@
      * @param s the array of string to test
      * @return true if all the strings in the array math XML-NMTOKEN
      */
-    protected boolean areNmtokens(String[] s) {
+    public static final boolean areNmtokens(String[] s) {
         for (int i = 0; i < s.length; i++) {
             if (!isNmtoken(s[i])) {
                 return false;
@@ -351,5 +420,26 @@
         }
         return true;
     }
+    }
+
+    /**
+     * Does this String match the XML-NMTOKEN production?
+     * @param s the string to test
+     * @return true if the string matches the XML-NMTOKEN
+     */
+    protected boolean isNmtoken(String s) {
+	return DTDPrinter.isNmtoken(s);
+    }
 
+    /**
+     * Do the Strings all match the XML-NMTOKEN production?
+     *
+     * <p>Otherwise they are not suitable as an enumerated attribute,
+     * for example.</p>
+     * @param s the array of string to test
+     * @return true if all the strings in the array math XML-NMTOKEN
+     */
+    protected boolean areNmtokens(String[] s) {
+	return DTDPrinter.areNmtokens(s);
+    }
 }

Modified: ant/core/trunk/src/testcases/org/apache/tools/ant/taskdefs/AntStructureTest.java
URL: http://svn.apache.org/viewcvs/ant/core/trunk/src/testcases/org/apache/tools/ant/taskdefs/AntStructureTest.java?rev=292244&r1=292243&r2=292244&view=diff
==============================================================================
--- ant/core/trunk/src/testcases/org/apache/tools/ant/taskdefs/AntStructureTest.java (original)
+++ ant/core/trunk/src/testcases/org/apache/tools/ant/taskdefs/AntStructureTest.java Wed Sep 28 11:34:04 2005
@@ -17,7 +17,12 @@
 
 package org.apache.tools.ant.taskdefs;
 
+import java.io.PrintWriter;
+import java.util.Hashtable;
+import junit.framework.Assert;
 import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.Project;
+
 /**
  */
 public class AntStructureTest extends BuildFileTest {
@@ -30,7 +35,62 @@
         configureProject("src/etc/testcases/taskdefs/antstructure.xml");
     }
 
+    public void tearDown() {
+	executeTarget("tearDown");
+    }
+
     public void test1() {
         expectBuildException("test1", "required argument not specified");
+    }
+
+    public void testCustomPrinter() {
+	executeTarget("testCustomPrinter");
+	// can't access the booleans in MyPrinter here (even if they
+	// were static) since the MyPrinter instance that was used in
+	// the test has likely been loaded via a different classloader
+	// than this class.  Therefore we make the printer assert its
+	// state and only check for the tail invocation.
+	assertLogContaining(MyPrinter.TAIL_CALLED);
+    }
+
+    public static class MyPrinter implements AntStructure.StructurePrinter {
+	private static final String TAIL_CALLED = "tail has been called";
+	private boolean headCalled = false;
+	private boolean targetCalled = false;
+	private boolean tailCalled = false;
+	private int elementCalled = 0;
+	private Project p;
+
+	public void printHead(PrintWriter out, Project p, Hashtable tasks,
+			      Hashtable types) {
+	    Assert.assertTrue(!headCalled);
+	    Assert.assertTrue(!targetCalled);
+	    Assert.assertTrue(!tailCalled);
+	    Assert.assertEquals(0, elementCalled);
+	    headCalled = true;
+	}
+	public void printTargetDecl(PrintWriter out) {
+	    Assert.assertTrue(headCalled);
+	    Assert.assertTrue(!targetCalled);
+	    Assert.assertTrue(!tailCalled);
+	    Assert.assertEquals(0, elementCalled);
+	    targetCalled = true;
+	}
+	public void printElementDecl(PrintWriter out, Project p, String name,
+				     Class element) {
+	    Assert.assertTrue(headCalled);
+	    Assert.assertTrue(targetCalled);
+	    Assert.assertTrue(!tailCalled);
+	    elementCalled++;
+	    this.p = p;
+	}
+	public void printTail(PrintWriter out) {
+	    Assert.assertTrue(headCalled);
+	    Assert.assertTrue(targetCalled);
+	    Assert.assertTrue(!tailCalled);
+	    Assert.assertTrue(elementCalled > 0);
+	    tailCalled = true;
+	    p.log(TAIL_CALLED);
+	}
     }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org