@@ -29,6 +29,7 @@ import java.util.Hashtable;
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 @@ import org.apache.tools.ant.types.Reference;
*/
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.
@@ -62,6 +58,14 @@ public class AntStructure extends Task {
this.output = output;
}
/**
* The StructurePrinter to use.
* @since Ant 1.7
*/
public void add(StructurePrinter p) {
printer = p;
}
/**
* Build the antstructure DTD.
*
@@ -87,25 +91,28 @@ public class AntStructure extends Task {
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.print TargetDecl(out);
Enumeration dataTypes = getProject().getDataTypeDefinitions().keys();
while (dataTypes.hasMoreElements()) {
String typeName = (String) dataTypes.nextElement();
printElementDecl(out, typeName,
printer.print ElementDecl(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.print ElementDecl(out, getProject() , tName,
(Class) getProject().getTaskDefinitions().get(tName));
}
printer.printTail(out);
} catch (IOException ioe) {
throw new BuildException("Error writing "
+ output.getAbsolutePath(), ioe, getLocation());
@@ -113,10 +120,72 @@ public class AntStructure extends Task {
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.
*
@@ -169,7 +238,7 @@ public class AntStructure extends Task {
/**
* 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 @@ public class AntStructure extends Task {
/**
* 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 @@ public class AntStructure extends Task {
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 @@ public class AntStructure extends Task {
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 @@ public class AntStructure extends Task {
* @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 @@ public class AntStructure extends Task {
* @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 @@ public class AntStructure extends Task {
}
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);
}
}