diff --git a/docs/manual/CoreTasks/presetdef.html b/docs/manual/CoreTasks/presetdef.html index 390c8a005..166d643af 100644 --- a/docs/manual/CoreTasks/presetdef.html +++ b/docs/manual/CoreTasks/presetdef.html @@ -3,10 +3,15 @@ PreSetDef Task + - +

PreSetDef

Description

@@ -43,35 +48,67 @@ This nested element can be any other type or task. The attributes and elements that need to be preset are placed here.

- +

Examples

-

- The following fragment defines a javac task with the debug and deprecation + The following fragment defines a javac task with the debug, deprecation + srcdir and destdir attributes set. It also has a src element to source files from a generated directory. -

-
+
 <presetdef name="my.javac">
-   <javac debug="${debug}" deprecation="${deprecation}">
+   <javac debug="${debug}" deprecation="${deprecation}"
+          srcdir="${src.dir}" destdir="${classes.dir}">
       <src path="${gen.dir}"/>
    </javac>
 </presetdef>
-      
+
-

This can be used as a normal javac task - example: -

-
-<my.javac src="${src.dir}" destdir="${classes.dir}"/>
-      
+
+<my.javac/>
+
- -
-

Copyright © 2003 Apache Software -Foundation. All rights Reserved.

- - + The attributes specified in the preset task may be overridden - i.e. + they may be seen as optional attributes - example: +
+
+<my.javac srcdir="${test.src}" deprecation="no"/>
+
+
+ One may put a presetdef definition in an antlib. + For example suppose the jar file antgoodies.jar has + the antlib.xml as follows: +
+
+<antlib>
+   <taskdef resource="com/acme/antgoodies/tasks.properties"/>
+   <!-- Implement the common use of the javac command -->
+   <presetdef name="javac">
+      <javac deprecation="${deprecation}" debug="${debug}"
+             srcdir="src" destdir="classes"/>
+   </presetdef>
+</antlib>
+
+
+ One may then use this in a build file as follows: +
+
+<project default="example" xmlns:antgoodies="antlib:com.acme.antgoodies">
+   <target name="example">
+      <!-- Compile source -->
+      <antgoodies:javac srcdir="src/main"/>
+      <!-- Compile test code -->
+      <antgoodies:javac srcdir="src/test"/>
+   </target>
+</project>
+
+
+
+

Copyright © 2003 Apache Software + Foundation. All rights Reserved.

+ + diff --git a/src/etc/testcases/taskdefs/presetdef.xml b/src/etc/testcases/taskdefs/presetdef.xml index f62373409..116ed58b0 100644 --- a/src/etc/testcases/taskdefs/presetdef.xml +++ b/src/etc/testcases/taskdefs/presetdef.xml @@ -1,20 +1,87 @@ + + + + + + Inner Text + + + + + + + + + + + + + + + + + + +
+
+ + + + + MyText + + + override text + + + + + + Line 1 + + + + Line 2 + + + + + + + Line 1 + + + + + Line 2 + + + + Line 3 + + + diff --git a/src/main/org/apache/tools/ant/IntrospectionHelper.java b/src/main/org/apache/tools/ant/IntrospectionHelper.java index ef01eb605..c7301d00d 100644 --- a/src/main/org/apache/tools/ant/IntrospectionHelper.java +++ b/src/main/org/apache/tools/ant/IntrospectionHelper.java @@ -65,6 +65,7 @@ import java.util.List; import java.util.Locale; import org.apache.tools.ant.types.EnumeratedAttribute; import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.taskdefs.PreSetDef; /** * Helper class that collects the methods a task or nested element @@ -286,11 +287,14 @@ public final class IntrospectionHelper implements BuildListener { if (nestedCreators.get(propName) == null) { nestedTypes.put(propName, returnType); nestedCreators.put(propName, new NestedCreator() { - public boolean isPolyMorphic() { return false; } + public Object getRealObject() { + return null; + } + public Class getElementClass() { return null; } @@ -332,6 +336,10 @@ public final class IntrospectionHelper implements BuildListener { return true; } + public Object getRealObject() { + return null; + } + public Class getElementClass() { return c.getDeclaringClass(); } @@ -387,6 +395,10 @@ public final class IntrospectionHelper implements BuildListener { return true; } + public Object getRealObject() { + return null; + } + public Class getElementClass() { return c.getDeclaringClass(); } @@ -611,6 +623,10 @@ public final class IntrospectionHelper implements BuildListener { return null; } + public Object getRealObject() { + return null; + } + public Object create( Project project, Object parent, Object ignore) { return nestedElement; @@ -1112,6 +1128,14 @@ public final class IntrospectionHelper implements BuildListener { } } + /** + * @return the real object (used currently only + * for preset def) + */ + public Object getRealObject() { + return nestedCreator.getRealObject(); + } + /** * Stores the nested element object using a storage method * determined by introspection. @@ -1147,6 +1171,7 @@ public final class IntrospectionHelper implements BuildListener { private interface NestedCreator { boolean isPolyMorphic(); Class getElementClass(); + Object getRealObject(); Object create(Project project, Object parent, Object child) throws InvocationTargetException, IllegalAccessException, InstantiationException; void store(Object parent, Object child) @@ -1252,8 +1277,14 @@ public final class IntrospectionHelper implements BuildListener { if (addedObject == null) { return null; } + Object rObject = addedObject; + if (addedObject instanceof PreSetDef.PreSetDefinition) { + rObject = ((PreSetDef.PreSetDefinition) addedObject).createObject( + project); + } final Method method = addMethod; final Object nestedObject = addedObject; + final Object realObject = rObject; return new NestedCreator() { public boolean isPolyMorphic() { @@ -1266,15 +1297,20 @@ public final class IntrospectionHelper implements BuildListener { public Object create(Project project, Object parent, Object ignore) throws InvocationTargetException, IllegalAccessException { if (!method.getName().endsWith("Configured")) { - method.invoke(parent, new Object[]{nestedObject}); + method.invoke(parent, new Object[]{realObject}); } return nestedObject; } + + public Object getRealObject() { + return realObject; + } + public void store(Object parent, Object child) throws InvocationTargetException, IllegalAccessException, InstantiationException { if (method.getName().endsWith("Configured")) { - method.invoke(parent, new Object[]{nestedObject}); + method.invoke(parent, new Object[]{realObject}); } } }; diff --git a/src/main/org/apache/tools/ant/RuntimeConfigurable.java b/src/main/org/apache/tools/ant/RuntimeConfigurable.java index 12236c645..f55181abc 100644 --- a/src/main/org/apache/tools/ant/RuntimeConfigurable.java +++ b/src/main/org/apache/tools/ant/RuntimeConfigurable.java @@ -63,6 +63,7 @@ import java.util.Hashtable; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Iterator; import org.apache.tools.ant.util.CollectionUtils; import org.xml.sax.AttributeList; @@ -222,7 +223,6 @@ public class RuntimeConfigurable implements Serializable { * @return Attribute name to attribute value map */ public Hashtable getAttributeMap() { - // Nobody calls this method, maybe it could just be deleted? if (attributeMap != null) { return new Hashtable(attributeMap); } else { @@ -464,4 +464,46 @@ public class RuntimeConfigurable implements Serializable { proxyConfigured = false; maybeConfigure(p); } + + + /** + * Apply presets, attributes and text are set if not currently set. + * nested elements are prepended. + * + * @param r a RuntimeConfigurable value + */ + public void applyPreSet(RuntimeConfigurable r) { + // Attributes + if (r.attributeMap != null) { + for (Iterator i = r.attributeMap.keySet().iterator(); i.hasNext();) { + String name = (String) i.next(); + if (attributeMap == null || attributeMap.get(name) == null) { + setAttribute(name, (String) r.attributeMap.get(name)); + } + } + } + // poly type + if (r.polyType != null && polyType == null) { + polyType = r.polyType; + } + + // Children (this is a shadow of unknownElement#children) + if (r.children != null) { + List newChildren = new ArrayList(); + newChildren.addAll(r.children); + if (children != null) { + newChildren.addAll(children); + } + children = newChildren; + } + + // Text + if (r.characters != null) { + if (characters == null + || characters.toString().trim().length() == 0) { + characters = + new StringBuffer(r.characters.toString()); + } + } + } } diff --git a/src/main/org/apache/tools/ant/UnknownElement.java b/src/main/org/apache/tools/ant/UnknownElement.java index a6844fa5c..3e7cf8cd3 100644 --- a/src/main/org/apache/tools/ant/UnknownElement.java +++ b/src/main/org/apache/tools/ant/UnknownElement.java @@ -58,6 +58,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.io.IOException; +import org.apache.tools.ant.taskdefs.PreSetDef; /** * Wrapper class that holds all the information necessary to create a task @@ -95,6 +96,9 @@ public class UnknownElement extends Task { */ private List/**/ children = null; + /** Specifies if a predefined definition has been done */ + private boolean presetDefed = false; + /** * Creates an UnknownElement for the given element name. * @@ -371,6 +375,31 @@ public class UnknownElement extends Task { return ProjectHelper.genComponentName(getNamespace(), getTag()); } + /** + * This is used then the realobject of the UE is a PreSetDefinition. + * This is also used when a presetdef is used on a presetdef + * The attributes, elements and text are applied to this + * UE. + * + * @param u an UnknownElement containing the attributes, elements and text + */ + public void applyPreSet(UnknownElement u) { + if (presetDefed) { + return; + } + // Do the runtime + getWrapper().applyPreSet(u.getWrapper()); + if (u.children != null) { + List newChildren = new ArrayList(); + newChildren.addAll(u.children); + if (children != null) { + newChildren.addAll(children); + } + children = newChildren; + } + presetDefed = true; + } + /** * Creates a named task or data type. If the real object is a task, * it is configured up to the init() stage. @@ -386,9 +415,17 @@ public class UnknownElement extends Task { getProject()); String name = ue.getComponentName(); Object o = helper.createComponent(ue, ue.getNamespace(), name); + if (o == null) { throw getNotFoundException("task or type", name); } + + if (o instanceof PreSetDef.PreSetDefinition) { + PreSetDef.PreSetDefinition def = (PreSetDef.PreSetDefinition) o; + o = def.createObject(ue.getProject()); + ue.applyPreSet(def.getPreSets()); + } + if (o instanceof Task) { Task task = (Task) o; task.setOwningTarget(getOwningTarget()); @@ -521,6 +558,12 @@ public class UnknownElement extends Task { ih.getElementCreator(getProject(), parent, childName); creator.setPolyType(childWrapper.getPolyType()); Object realChild = creator.create(); + if (realChild instanceof PreSetDef.PreSetDefinition) { + PreSetDef.PreSetDefinition def = + (PreSetDef.PreSetDefinition) realChild; + realChild = creator.getRealObject(); + child.applyPreSet(def.getPreSets()); + } childWrapper.setCreator(creator); childWrapper.setProxy(realChild); if (realChild instanceof Task) { diff --git a/src/main/org/apache/tools/ant/taskdefs/PreSetDef.java b/src/main/org/apache/tools/ant/taskdefs/PreSetDef.java index 8dc78f86e..19a8d0c0f 100644 --- a/src/main/org/apache/tools/ant/taskdefs/PreSetDef.java +++ b/src/main/org/apache/tools/ant/taskdefs/PreSetDef.java @@ -130,26 +130,52 @@ public class PreSetDef extends AntlibDefinition implements TaskContainer { "Unable to find typedef " + componentName); } - MyAntTypeDefinition newDef = new MyAntTypeDefinition(def, nestedTask); + PreSetDefinition newDef = new PreSetDefinition(def, nestedTask); newDef.setName(name); helper.addDataTypeDefinition(newDef); } - private static class MyAntTypeDefinition extends AntTypeDefinition { + /** + * This class contains the unknown element and the object + * that is predefined. + * @see AntTypeDefinition + */ + public static class PreSetDefinition extends AntTypeDefinition { private AntTypeDefinition parent; private UnknownElement element; - public MyAntTypeDefinition(AntTypeDefinition parent, UnknownElement el) { + /** + * Creates a new PresetDefinition instance. + * + * @param parent The parent of this predefintion. + * @param el The predefined attributes, nested elements and text. + */ + public PreSetDefinition(AntTypeDefinition parent, UnknownElement el) { + if (parent instanceof PreSetDefinition) { + PreSetDefinition p = (PreSetDefinition) parent; + el.applyPreSet(p.element); + parent = p.parent; + } this.parent = parent; this.element = el; } + /** + * Override so that it is not allowed + * + * @param clazz a Class value + */ public void setClass(Class clazz) { throw new BuildException("Not supported"); } + /** + * Override so that it is not allowed + * + * @param className a String value + */ public void setClassName(String className) { throw new BuildException("Not supported"); } @@ -200,6 +226,7 @@ public class PreSetDef extends AntlibDefinition implements TaskContainer { /** * get the exposed class for this definition. + * @param project the current project * @return the exposed class */ public Class getExposedClass(Project project) { @@ -227,18 +254,37 @@ public class PreSetDef extends AntlibDefinition implements TaskContainer { /** * create an instance of the definition. * The instance may be wrapped in a proxy class. + * This is a special version of create for IH and UE. * @param project the current project * @return the created object */ - public Object create(Project project) { + public Object createObject(Project project) { Object o = parent.create(project); if (o == null) { return null; } - element.configure(o); return o; } + /** + * @return the predefined attributes, elements and text as + * a UnknownElement + */ + public UnknownElement getPreSets() { + return element; + } + + /** + * Fake create an object, used by IH and UE to see that + * this is a predefined object. + * + * @param project the current project + * @return this object + */ + public Object create(Project project) { + return this; + } + /** * Equality method for this definition * @@ -253,7 +299,7 @@ public class PreSetDef extends AntlibDefinition implements TaskContainer { if (other.getClass() != getClass()) { return false; } - MyAntTypeDefinition otherDef = (MyAntTypeDefinition) other; + PreSetDefinition otherDef = (PreSetDefinition) other; if (!parent.sameDefinition(otherDef.parent, project)) { return false; } @@ -278,7 +324,7 @@ public class PreSetDef extends AntlibDefinition implements TaskContainer { if (!other.getClass().getName().equals(getClass().getName())) { return false; } - MyAntTypeDefinition otherDef = (MyAntTypeDefinition) other; + PreSetDefinition otherDef = (PreSetDefinition) other; if (!parent.similarDefinition(otherDef.parent, project)) { return false; } diff --git a/src/testcases/org/apache/tools/ant/taskdefs/PreSetDefTest.java b/src/testcases/org/apache/tools/ant/taskdefs/PreSetDefTest.java index 2bce11a2d..f4561fb13 100644 --- a/src/testcases/org/apache/tools/ant/taskdefs/PreSetDefTest.java +++ b/src/testcases/org/apache/tools/ant/taskdefs/PreSetDefTest.java @@ -55,6 +55,7 @@ package org.apache.tools.ant.taskdefs; import org.apache.tools.ant.BuildFileTest; +import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; @@ -82,5 +83,43 @@ public class PreSetDefTest extends BuildFileTest { expectLog("uri", "Hello world"); } + public void testDefaultTest() { + expectLog("defaulttest", "attribute is false"); + } + + public void testDoubleDefault() { + expectLog("doubledefault", "attribute is falseattribute is true"); + } + + public void testTextOptional() { + expectLog("text.optional", "MyTextoverride text"); + } + + public void testElementOrder() { + expectLog("element.order", "Line 1Line 2"); + } + + public void testElementOrder2() { + expectLog("element.order2", "Line 1Line 2Line 3"); + } + + /** + * A test class to check default properties + */ + public static class DefaultTest extends Task { + boolean isSet = false; + boolean attribute = false; + public void setAttribute(boolean b) { + if (isSet) { + throw new BuildException("Attribute Already set"); + } + attribute = b; + isSet = true; + } + + public void execute() { + getProject().log("attribute is " + attribute); + } + } }