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>
<meta http-equiv="Content-Language" content="en-us"></meta>
<title>PreSetDef Task</title>
<style type="text/css">
<!--
.code { background: #EFEFEF; margin-top: }
-->
</style>
</head>
<body>

<h2><a name="presetdef">PreSetDef</a></h2>
<h3>Description</h3>
<p>
@@ -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.
</p>
<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
directory.
</p>
<blockquote>
<pre>
<pre class="code">
&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;/javac&gt;
&lt;/presetdef&gt;
</pre>
</pre>
</blockquote>
<p>
This can be used as a normal javac task - example:
</p>
<blockquote>
<pre>
&lt;my.javac src="${src.dir}" destdir="${classes.dir}"/&gt;
</pre>
<pre class="code">
&lt;my.javac/&gt;
</pre>
</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>


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

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

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

<target name="uri">
<presetdef name="echo" uri="abc">
<echo message="Hello world"/>
</presetdef>
<x:echo xmlns:x="abc"/>
</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>

+ 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 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});
}
}
};


+ 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.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 <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.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/*<UnknownElement>*/ 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) {


+ 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);
}

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 <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.element = el;
}

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

/**
* Override so that it is not allowed
*
* @param className a <code>String</code> 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;
}


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

@@ -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);
}
}
}


Loading…
Cancel
Save