Browse Source

fixes for presetdef's handling of attributes

PR: 24411


git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@275617 13f79535-47bb-0310-9956-ffa450edef68
master
Peter Reilly 21 years ago
parent
commit
47fa568d32
7 changed files with 340 additions and 30 deletions
  1. +56
    -19
      docs/manual/CoreTasks/presetdef.html
  2. +67
    -0
      src/etc/testcases/taskdefs/presetdef.xml
  3. +39
    -3
      src/main/org/apache/tools/ant/IntrospectionHelper.java
  4. +43
    -1
      src/main/org/apache/tools/ant/RuntimeConfigurable.java
  5. +43
    -0
      src/main/org/apache/tools/ant/UnknownElement.java
  6. +53
    -7
      src/main/org/apache/tools/ant/taskdefs/PreSetDef.java
  7. +39
    -0
      src/testcases/org/apache/tools/ant/taskdefs/PreSetDefTest.java

+ 56
- 19
docs/manual/CoreTasks/presetdef.html View File

@@ -3,10 +3,15 @@
<head> <head>
<meta http-equiv="Content-Language" content="en-us"></meta> <meta http-equiv="Content-Language" content="en-us"></meta>
<title>PreSetDef Task</title> <title>PreSetDef Task</title>
<style type="text/css">
<!--
.code { background: #EFEFEF; margin-top: }
-->
</style>
</head> </head>
<body> <body>

<h2><a name="presetdef">PreSetDef</a></h2> <h2><a name="presetdef">PreSetDef</a></h2>
<h3>Description</h3> <h3>Description</h3>
<p> <p>
@@ -43,35 +48,67 @@
This nested element can be any other type or task. The attributes This nested element can be any other type or task. The attributes
and elements that need to be preset are placed here. and elements that need to be preset are placed here.
</p> </p>
<h3>Examples</h3> <h3>Examples</h3>
<p>
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 attributes set. It also has a src element to source files from a generated
directory. directory.
</p>
<blockquote> <blockquote>
<pre>
<pre class="code">
&lt;presetdef name="my.javac"&gt; &lt;presetdef name="my.javac"&gt;
&lt;javac debug="${debug}" deprecation="${deprecation}"&gt;
&lt;javac debug="${debug}" deprecation="${deprecation}"
srcdir="${src.dir}" destdir="${classes.dir}"&gt;
&lt;src path="${gen.dir}"/&gt; &lt;src path="${gen.dir}"/&gt;
&lt;/javac&gt; &lt;/javac&gt;
&lt;/presetdef&gt; &lt;/presetdef&gt;
</pre>
</pre>
</blockquote> </blockquote>
<p>
This can be used as a normal javac task - example: This can be used as a normal javac task - example:
</p>
<blockquote> <blockquote>
<pre>
&lt;my.javac src="${src.dir}" destdir="${classes.dir}"/&gt;
</pre>
<pre class="code">
&lt;my.javac/&gt;
</pre>
</blockquote> </blockquote>

<hr>
<p align="center">Copyright &copy; 2003 Apache Software
Foundation. All rights Reserved.</p>

</body>
The attributes specified in the preset task may be overridden - i.e.
they may be seen as optional attributes - example:
<blockquote>
<pre class="code">
&lt;my.javac srcdir="${test.src}" deprecation="no"/&gt;
</pre>
</blockquote>
One may put a presetdef definition in an antlib.
For example suppose the jar file antgoodies.jar has
the antlib.xml as follows:
<blockquote>
<pre class="code">
&lt;antlib&gt;
&lt;taskdef resource="com/acme/antgoodies/tasks.properties"/&gt;
&lt;!-- Implement the common use of the javac command --&gt;
&lt;presetdef name="javac"&gt;
&lt;javac deprecation="${deprecation}" debug="${debug}"
srcdir="src" destdir="classes"/&gt;
&lt;/presetdef&gt;
&lt;/antlib&gt;
</pre>
</blockquote>
One may then use this in a build file as follows:
<blockquote>
<pre class="code">
&lt;project default="example" xmlns:antgoodies="antlib:com.acme.antgoodies"&gt;
&lt;target name="example"&gt;
&lt;!-- Compile source --&gt;
&lt;antgoodies:javac srcdir="src/main"/&gt;
&lt;!-- Compile test code --&gt;
&lt;antgoodies:javac srcdir="src/test"/&gt;
&lt;/target&gt;
&lt;/project&gt;
</pre>
</blockquote>
<hr></hr>
<p align="center">Copyright &copy; 2003 Apache Software
Foundation. All rights Reserved.</p>
</body>
</html> </html>



+ 67
- 0
src/etc/testcases/taskdefs/presetdef.xml View File

@@ -1,20 +1,87 @@
<project> <project>
<path id="test-classes">
<pathelement location="../../../../build/testcases" />
<pathelement path="${java.class.path}" />
</path>
<target name="simple"> <target name="simple">
<presetdef name="my.echo"> <presetdef name="my.echo">
<echo message="Hello world"/> <echo message="Hello world"/>
</presetdef> </presetdef>
<my.echo/> <my.echo/>
</target> </target>

<target name="text"> <target name="text">
<presetdef name="my.echo"> <presetdef name="my.echo">
<echo>Inner Text</echo> <echo>Inner Text</echo>
</presetdef> </presetdef>
<my.echo/> <my.echo/>
</target> </target>

<target name="uri"> <target name="uri">
<presetdef name="echo" uri="abc"> <presetdef name="echo" uri="abc">
<echo message="Hello world"/> <echo message="Hello world"/>
</presetdef> </presetdef>
<x:echo xmlns:x="abc"/> <x:echo xmlns:x="abc"/>
</target> </target>

<target name="defaulttest">
<taskdef name="defaulttest"
classname="org.apache.tools.ant.taskdefs.PreSetDefTest$DefaultTest"
classpathref="test-classes"/>
<presetdef name="d">
<defaulttest attribute="true"/>
</presetdef>
<d attribute="false"/>
</target>

<target name="doubledefault">
<taskdef name="defaulttest"
classname="org.apache.tools.ant.taskdefs.PreSetDefTest$DefaultTest"
classpathref="test-classes"/>
<presetdef name="d">
<defaulttest attribute="true"/>
</presetdef>
<presetdef name="dd">
<d attribute="false"/>
</presetdef>
<dd/>
<dd attribute="true"/>
</target>

<target name="text.optional">
<presetdef name="echo.mytext">
<echo>MyText</echo>
</presetdef>
<echo.mytext/>
<echo.mytext>override text</echo.mytext>
</target>

<target name="element.order">
<presetdef name="el.order">
<sequential>
<echo>Line 1</echo>
</sequential>
</presetdef>
<el.order>
<echo>Line 2</echo>
</el.order>
</target>

<target name="element.order2">
<presetdef name="el.order">
<sequential>
<echo>Line 1</echo>
</sequential>
</presetdef>
<presetdef name="el.order2">
<el.order>
<echo>Line 2</echo>
</el.order>
</presetdef>
<el.order2>
<echo>Line 3</echo>
</el.order2>
</target>

</project> </project>

+ 39
- 3
src/main/org/apache/tools/ant/IntrospectionHelper.java View File

@@ -65,6 +65,7 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import org.apache.tools.ant.types.EnumeratedAttribute; import org.apache.tools.ant.types.EnumeratedAttribute;
import org.apache.tools.ant.types.Path; 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 * 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) { if (nestedCreators.get(propName) == null) {
nestedTypes.put(propName, returnType); nestedTypes.put(propName, returnType);
nestedCreators.put(propName, new NestedCreator() { nestedCreators.put(propName, new NestedCreator() {

public boolean isPolyMorphic() { public boolean isPolyMorphic() {
return false; return false;
} }


public Object getRealObject() {
return null;
}

public Class getElementClass() { public Class getElementClass() {
return null; return null;
} }
@@ -332,6 +336,10 @@ public final class IntrospectionHelper implements BuildListener {
return true; return true;
} }


public Object getRealObject() {
return null;
}

public Class getElementClass() { public Class getElementClass() {
return c.getDeclaringClass(); return c.getDeclaringClass();
} }
@@ -387,6 +395,10 @@ public final class IntrospectionHelper implements BuildListener {
return true; return true;
} }


public Object getRealObject() {
return null;
}

public Class getElementClass() { public Class getElementClass() {
return c.getDeclaringClass(); return c.getDeclaringClass();
} }
@@ -611,6 +623,10 @@ public final class IntrospectionHelper implements BuildListener {
return null; return null;
} }


public Object getRealObject() {
return null;
}

public Object create( public Object create(
Project project, Object parent, Object ignore) { Project project, Object parent, Object ignore) {
return nestedElement; 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 * Stores the nested element object using a storage method
* determined by introspection. * determined by introspection.
@@ -1147,6 +1171,7 @@ public final class IntrospectionHelper implements BuildListener {
private interface NestedCreator { private interface NestedCreator {
boolean isPolyMorphic(); boolean isPolyMorphic();
Class getElementClass(); Class getElementClass();
Object getRealObject();
Object create(Project project, Object parent, Object child) Object create(Project project, Object parent, Object child)
throws InvocationTargetException, IllegalAccessException, InstantiationException; throws InvocationTargetException, IllegalAccessException, InstantiationException;
void store(Object parent, Object child) void store(Object parent, Object child)
@@ -1252,8 +1277,14 @@ public final class IntrospectionHelper implements BuildListener {
if (addedObject == null) { if (addedObject == null) {
return null; return null;
} }
Object rObject = addedObject;
if (addedObject instanceof PreSetDef.PreSetDefinition) {
rObject = ((PreSetDef.PreSetDefinition) addedObject).createObject(
project);
}
final Method method = addMethod; final Method method = addMethod;
final Object nestedObject = addedObject; final Object nestedObject = addedObject;
final Object realObject = rObject;


return new NestedCreator() { return new NestedCreator() {
public boolean isPolyMorphic() { public boolean isPolyMorphic() {
@@ -1266,15 +1297,20 @@ public final class IntrospectionHelper implements BuildListener {
public Object create(Project project, Object parent, Object ignore) public Object create(Project project, Object parent, Object ignore)
throws InvocationTargetException, IllegalAccessException { throws InvocationTargetException, IllegalAccessException {
if (!method.getName().endsWith("Configured")) { if (!method.getName().endsWith("Configured")) {
method.invoke(parent, new Object[]{nestedObject});
method.invoke(parent, new Object[]{realObject});
} }
return nestedObject; return nestedObject;
} }

public Object getRealObject() {
return realObject;
}

public void store(Object parent, Object child) public void store(Object parent, Object child)
throws InvocationTargetException, IllegalAccessException, throws InvocationTargetException, IllegalAccessException,
InstantiationException { InstantiationException {
if (method.getName().endsWith("Configured")) { if (method.getName().endsWith("Configured")) {
method.invoke(parent, new Object[]{nestedObject});
method.invoke(parent, new Object[]{realObject});
} }
} }
}; };


+ 43
- 1
src/main/org/apache/tools/ant/RuntimeConfigurable.java View File

@@ -63,6 +63,7 @@ import java.util.Hashtable;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Iterator;


import org.apache.tools.ant.util.CollectionUtils; import org.apache.tools.ant.util.CollectionUtils;
import org.xml.sax.AttributeList; import org.xml.sax.AttributeList;
@@ -222,7 +223,6 @@ public class RuntimeConfigurable implements Serializable {
* @return Attribute name to attribute value map * @return Attribute name to attribute value map
*/ */
public Hashtable getAttributeMap() { public Hashtable getAttributeMap() {
// Nobody calls this method, maybe it could just be deleted?
if (attributeMap != null) { if (attributeMap != null) {
return new Hashtable(attributeMap); return new Hashtable(attributeMap);
} else { } else {
@@ -464,4 +464,46 @@ public class RuntimeConfigurable implements Serializable {
proxyConfigured = false; proxyConfigured = false;
maybeConfigure(p); maybeConfigure(p);
} }


/**
* Apply presets, attributes and text are set if not currently set.
* nested elements are prepended.
*
* @param r a <code>RuntimeConfigurable</code> 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());
}
}
}
} }

+ 43
- 0
src/main/org/apache/tools/ant/UnknownElement.java View File

@@ -58,6 +58,7 @@ import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.io.IOException; import java.io.IOException;
import org.apache.tools.ant.taskdefs.PreSetDef;


/** /**
* Wrapper class that holds all the information necessary to create a task * Wrapper class that holds all the information necessary to create a task
@@ -95,6 +96,9 @@ public class UnknownElement extends Task {
*/ */
private List/*<UnknownElement>*/ children = null; private List/*<UnknownElement>*/ children = null;


/** Specifies if a predefined definition has been done */
private boolean presetDefed = false;

/** /**
* Creates an UnknownElement for the given element name. * Creates an UnknownElement for the given element name.
* *
@@ -371,6 +375,31 @@ public class UnknownElement extends Task {
return ProjectHelper.genComponentName(getNamespace(), getTag()); 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, * Creates a named task or data type. If the real object is a task,
* it is configured up to the init() stage. * it is configured up to the init() stage.
@@ -386,9 +415,17 @@ public class UnknownElement extends Task {
getProject()); getProject());
String name = ue.getComponentName(); String name = ue.getComponentName();
Object o = helper.createComponent(ue, ue.getNamespace(), name); Object o = helper.createComponent(ue, ue.getNamespace(), name);

if (o == null) { if (o == null) {
throw getNotFoundException("task or type", name); 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) { if (o instanceof Task) {
Task task = (Task) o; Task task = (Task) o;
task.setOwningTarget(getOwningTarget()); task.setOwningTarget(getOwningTarget());
@@ -521,6 +558,12 @@ public class UnknownElement extends Task {
ih.getElementCreator(getProject(), parent, childName); ih.getElementCreator(getProject(), parent, childName);
creator.setPolyType(childWrapper.getPolyType()); creator.setPolyType(childWrapper.getPolyType());
Object realChild = creator.create(); 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.setCreator(creator);
childWrapper.setProxy(realChild); childWrapper.setProxy(realChild);
if (realChild instanceof Task) { if (realChild instanceof Task) {


+ 53
- 7
src/main/org/apache/tools/ant/taskdefs/PreSetDef.java View File

@@ -130,26 +130,52 @@ public class PreSetDef extends AntlibDefinition implements TaskContainer {
"Unable to find typedef " + componentName); "Unable to find typedef " + componentName);
} }


MyAntTypeDefinition newDef = new MyAntTypeDefinition(def, nestedTask);
PreSetDefinition newDef = new PreSetDefinition(def, nestedTask);


newDef.setName(name); newDef.setName(name);


helper.addDataTypeDefinition(newDef); 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 AntTypeDefinition parent;
private UnknownElement element; private UnknownElement element;


public MyAntTypeDefinition(AntTypeDefinition parent, UnknownElement el) {
/**
* Creates a new <code>PresetDefinition</code> 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.parent = parent;
this.element = el; this.element = el;
} }


/**
* Override so that it is not allowed
*
* @param clazz a <code>Class</code> value
*/
public void setClass(Class clazz) { public void setClass(Class clazz) {
throw new BuildException("Not supported"); throw new BuildException("Not supported");
} }


/**
* Override so that it is not allowed
*
* @param className a <code>String</code> value
*/
public void setClassName(String className) { public void setClassName(String className) {
throw new BuildException("Not supported"); throw new BuildException("Not supported");
} }
@@ -200,6 +226,7 @@ public class PreSetDef extends AntlibDefinition implements TaskContainer {


/** /**
* get the exposed class for this definition. * get the exposed class for this definition.
* @param project the current project
* @return the exposed class * @return the exposed class
*/ */
public Class getExposedClass(Project project) { public Class getExposedClass(Project project) {
@@ -227,18 +254,37 @@ public class PreSetDef extends AntlibDefinition implements TaskContainer {
/** /**
* create an instance of the definition. * create an instance of the definition.
* The instance may be wrapped in a proxy class. * 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 * @param project the current project
* @return the created object * @return the created object
*/ */
public Object create(Project project) {
public Object createObject(Project project) {
Object o = parent.create(project); Object o = parent.create(project);
if (o == null) { if (o == null) {
return null; return null;
} }
element.configure(o);
return 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 * Equality method for this definition
* *
@@ -253,7 +299,7 @@ public class PreSetDef extends AntlibDefinition implements TaskContainer {
if (other.getClass() != getClass()) { if (other.getClass() != getClass()) {
return false; return false;
} }
MyAntTypeDefinition otherDef = (MyAntTypeDefinition) other;
PreSetDefinition otherDef = (PreSetDefinition) other;
if (!parent.sameDefinition(otherDef.parent, project)) { if (!parent.sameDefinition(otherDef.parent, project)) {
return false; return false;
} }
@@ -278,7 +324,7 @@ public class PreSetDef extends AntlibDefinition implements TaskContainer {
if (!other.getClass().getName().equals(getClass().getName())) { if (!other.getClass().getName().equals(getClass().getName())) {
return false; return false;
} }
MyAntTypeDefinition otherDef = (MyAntTypeDefinition) other;
PreSetDefinition otherDef = (PreSetDefinition) other;
if (!parent.similarDefinition(otherDef.parent, project)) { if (!parent.similarDefinition(otherDef.parent, project)) {
return false; return false;
} }


+ 39
- 0
src/testcases/org/apache/tools/ant/taskdefs/PreSetDefTest.java View File

@@ -55,6 +55,7 @@
package org.apache.tools.ant.taskdefs; package org.apache.tools.ant.taskdefs;


import org.apache.tools.ant.BuildFileTest; import org.apache.tools.ant.BuildFileTest;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project; import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task; import org.apache.tools.ant.Task;


@@ -82,5 +83,43 @@ public class PreSetDefTest extends BuildFileTest {
expectLog("uri", "Hello world"); 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);
}
}
} }



Loading…
Cancel
Save