diff --git a/docs/manual/CoreTasks/macrodef.html b/docs/manual/CoreTasks/macrodef.html
index da6de2409..595e7a168 100644
--- a/docs/manual/CoreTasks/macrodef.html
+++ b/docs/manual/CoreTasks/macrodef.html
@@ -131,6 +131,17 @@
description |
@@ -254,6 +265,45 @@
<linker refid="linker-libs"/>
</cc-elements>
</call-cc>
+
+
+
+ The following fragment shows <call-cc>, but this time
+ using an implicit element and with the link and target.dir arguments
+ having default values.
+
+
+
+<macrodef name="call-cc">
+ <attribute name="target"/>
+ <attribute name="link" default="executable"/>
+ <attribute name="target.dir" default="${build.bin.dir}"/>
+ <element name="cc-elements" implicit="yes"/>
+ <sequential>
+ <mkdir dir="${obj.dir}/@{target}"/>
+ <mkdir dir="@{target.dir}"/>
+ <cc link="@{link}" objdir="${obj.dir}/@{target}"
+ outfile="@{target.dir}/@{target}">
+ <compiler refid="compiler.options"/>
+ <cc-elements/>
+ </cc>
+ </sequential>
+</macrodef>
+
+
+
+ This then can be used as follows, note that <cc-elements>
+ is not specified.
+
+
+
+<call-cc target="unittests"/>
+ <includepath location="${gen.dir}"/>
+ <includepath location="test"/>
+ <fileset dir="test/unittest" includes = "**/*.cpp"/>
+ <fileset dir="${gen.dir}" includes = "*.cpp"/>
+ <linker refid="linker-libs"/>
+</call-cc>
diff --git a/src/etc/testcases/taskdefs/macrodef.xml b/src/etc/testcases/taskdefs/macrodef.xml
index b64418c72..fac274a1b 100644
--- a/src/etc/testcases/taskdefs/macrodef.xml
+++ b/src/etc/testcases/taskdefs/macrodef.xml
@@ -168,4 +168,59 @@
+
+
+
+
+ Before implicit
+
+ After implicit
+
+
+
+
+ In implicit
+
+
+
+
+
+
+
+ Before implicit
+
+ After implicit
+
+
+
+
+
+
+
+
+
+
+
+ Before implicit
+
+ After implicit
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/org/apache/tools/ant/DynamicAttribute.java b/src/main/org/apache/tools/ant/DynamicAttribute.java
new file mode 100644
index 000000000..b1e33d663
--- /dev/null
+++ b/src/main/org/apache/tools/ant/DynamicAttribute.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2002-2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+/**
+ * Enables a task to control unknown attributes
+ *
+ * @since Ant 1.5
+ */
+public interface DynamicAttribute {
+
+ /**
+ * Set a named attribute to the given value
+ *
+ * @param name the name of the attribute
+ * @param value the new value of the attribute
+ * @throws BuildException when any error occurs
+ */
+ void setDynamicAttribute(String name, String value)
+ throws BuildException;
+
+}
diff --git a/src/main/org/apache/tools/ant/DynamicAttributeNS.java b/src/main/org/apache/tools/ant/DynamicAttributeNS.java
new file mode 100644
index 000000000..27c8a8e6e
--- /dev/null
+++ b/src/main/org/apache/tools/ant/DynamicAttributeNS.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant;
+
+/**
+ * Enables a task to control unknown attributes.
+ *
+ * @since Ant 1.7
+ */
+public interface DynamicAttributeNS {
+
+ /**
+ * Set a named attribute to the given value
+ *
+ * @param uri The namespace uri for this attribute, "" is
+ * used if there is no namespace uri.
+ * @param localName The localname of this attribute.
+ * @param qName The qualified name for this attribute
+ * @param value The value of this attribute.
+ * @throws BuildException when any error occurs
+ */
+ void setDynamicAttribute(
+ String uri, String localName, String qName, String value)
+ throws BuildException;
+
+}
diff --git a/src/main/org/apache/tools/ant/DynamicElement.java b/src/main/org/apache/tools/ant/DynamicElement.java
new file mode 100644
index 000000000..30b84007f
--- /dev/null
+++ b/src/main/org/apache/tools/ant/DynamicElement.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2002-2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+/**
+ * Enables a task to control unknown elements.
+ *
+ * @since Ant 1.5
+ */
+public interface DynamicElement {
+
+ /**
+ * Create an element with the given name
+ *
+ * @param name the element nbame
+ * @throws BuildException when any error occurs
+ * @return the element created
+ */
+ Object createDynamicElement(String name) throws BuildException;
+}
diff --git a/src/main/org/apache/tools/ant/DynamicElementNS.java b/src/main/org/apache/tools/ant/DynamicElementNS.java
new file mode 100644
index 000000000..3a27a3dee
--- /dev/null
+++ b/src/main/org/apache/tools/ant/DynamicElementNS.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant;
+
+/**
+ * Enables a task to control unknown elements.
+ *
+ * @since Ant 1.7
+ */
+public interface DynamicElementNS {
+ /**
+ * Create an element with the given name
+ *
+ * @param uri The namespace uri for this attribute.
+ * @param localName The localname of this attribute.
+ * @param qName The qualified name for this element.
+ * @throws BuildException when any error occurs
+ * @return the element created for this element.
+ */
+ Object createDynamicElement(
+ String uri, String localName, String qName) throws BuildException;
+}
diff --git a/src/main/org/apache/tools/ant/IntrospectionHelper.java b/src/main/org/apache/tools/ant/IntrospectionHelper.java
index 63661ebee..aa50722a8 100644
--- a/src/main/org/apache/tools/ant/IntrospectionHelper.java
+++ b/src/main/org/apache/tools/ant/IntrospectionHelper.java
@@ -489,8 +489,8 @@ public final class IntrospectionHelper implements BuildListener {
= (AttributeSetter) attributeSetters.get(
attributeName.toLowerCase(Locale.US));
if (as == null) {
- if (element instanceof DynamicConfiguratorNS) {
- DynamicConfiguratorNS dc = (DynamicConfiguratorNS) element;
+ if (element instanceof DynamicAttributeNS) {
+ DynamicAttributeNS dc = (DynamicAttributeNS) element;
String uriPlusPrefix =
ProjectHelper.extractUriFromComponentName(attributeName);
String uri =
@@ -502,8 +502,8 @@ public final class IntrospectionHelper implements BuildListener {
dc.setDynamicAttribute(uri, localName, qName, value);
return;
- } else if (element instanceof DynamicConfigurator) {
- DynamicConfigurator dc = (DynamicConfigurator) element;
+ } else if (element instanceof DynamicAttribute) {
+ DynamicAttribute dc = (DynamicAttribute) element;
dc.setDynamicAttribute(attributeName.toLowerCase(Locale.US), value);
return;
} else {
@@ -611,8 +611,8 @@ public final class IntrospectionHelper implements BuildListener {
if (nc == null) {
nc = createAddTypeCreator(project, parent, elementName);
}
- if (nc == null && parent instanceof DynamicConfiguratorNS) {
- DynamicConfiguratorNS dc = (DynamicConfiguratorNS) parent;
+ if (nc == null && parent instanceof DynamicElementNS) {
+ DynamicElementNS dc = (DynamicElementNS) parent;
String qName = (child == null ? name : child.getQName());
final Object nestedElement =
dc.createDynamicElement(
@@ -640,8 +640,8 @@ public final class IntrospectionHelper implements BuildListener {
};
}
}
- if (nc == null && parent instanceof DynamicConfigurator) {
- DynamicConfigurator dc = (DynamicConfigurator) parent;
+ if (nc == null && parent instanceof DynamicElement) {
+ DynamicElement dc = (DynamicElement) parent;
final Object nestedElement =
dc.createDynamicElement(name.toLowerCase(Locale.US));
if (nestedElement != null) {
@@ -749,8 +749,8 @@ public final class IntrospectionHelper implements BuildListener {
*/
public boolean supportsNestedElement(String elementName) {
return nestedCreators.containsKey(elementName.toLowerCase(Locale.US))
- || DynamicConfigurator.class.isAssignableFrom(bean)
- || DynamicConfiguratorNS.class.isAssignableFrom(bean)
+ || DynamicElement.class.isAssignableFrom(bean)
+ || DynamicElementNS.class.isAssignableFrom(bean)
|| addTypeMethods.size() != 0;
}
@@ -776,8 +776,8 @@ public final class IntrospectionHelper implements BuildListener {
return (
nestedCreators.containsKey(name.toLowerCase(Locale.US))
&& (uri.equals(parentUri))) // || uri.equals("")))
- || DynamicConfigurator.class.isAssignableFrom(bean)
- || DynamicConfiguratorNS.class.isAssignableFrom(bean)
+ || DynamicElement.class.isAssignableFrom(bean)
+ || DynamicElementNS.class.isAssignableFrom(bean)
|| addTypeMethods.size() != 0;
}
diff --git a/src/main/org/apache/tools/ant/UnknownElement.java b/src/main/org/apache/tools/ant/UnknownElement.java
index e8986cb10..c75fe9b4f 100644
--- a/src/main/org/apache/tools/ant/UnknownElement.java
+++ b/src/main/org/apache/tools/ant/UnknownElement.java
@@ -71,6 +71,13 @@ public class UnknownElement extends Task {
this.elementName = elementName;
}
+ /**
+ * @return the list of nested UnknownElements for this UnknownElement.
+ */
+ public List getChildren() {
+ return children;
+ }
+
/**
* Returns the name of the XML element which generated this unknown
* element.
diff --git a/src/main/org/apache/tools/ant/taskdefs/MacroDef.java b/src/main/org/apache/tools/ant/taskdefs/MacroDef.java
index a25f3c923..38cc97544 100644
--- a/src/main/org/apache/tools/ant/taskdefs/MacroDef.java
+++ b/src/main/org/apache/tools/ant/taskdefs/MacroDef.java
@@ -46,6 +46,7 @@ public class MacroDef extends AntlibDefinition {
private Map elements = new HashMap();
private String textName = null;
private Text text = null;
+ private boolean hasImplicitElement = false;
/**
* Name of the definition
@@ -254,6 +255,12 @@ public class MacroDef extends AntlibDefinition {
"the element " + element.getName()
+ " has already been specified");
}
+ if (hasImplicitElement
+ || (element.isImplicit() && elements.size() != 0)) {
+ throw new BuildException(
+ "Only one element allowed when using implicit elements");
+ }
+ hasImplicitElement = element.isImplicit();
elements.put(element.getName(), element);
}
@@ -507,6 +514,7 @@ public class MacroDef extends AntlibDefinition {
public static class TemplateElement {
private String name;
private boolean optional = false;
+ private boolean implicit = false;
private String description;
/**
@@ -546,6 +554,23 @@ public class MacroDef extends AntlibDefinition {
return optional;
}
+ /**
+ * is this element implicit ?
+ *
+ * @param implicit if true this element may be left out, default
+ * is false.
+ */
+ public void setImplicit(boolean implicit) {
+ this.implicit = implicit;
+ }
+
+ /**
+ * @return the implicit attribute
+ */
+ public boolean isImplicit() {
+ return implicit;
+ }
+
/**
* @param desc Description of the element.
* @since ant 1.6.1
@@ -584,14 +609,15 @@ public class MacroDef extends AntlibDefinition {
} else if (!name.equals(other.name)) {
return false;
}
- return optional == other.optional;
+ return optional == other.optional && implicit == other.implicit;
}
/**
* @return a hash code value for this object.
*/
public int hashCode() {
- return objectHashCode(name) + (optional ? 1 : 0);
+ return objectHashCode(name)
+ + (optional ? 1 : 0) + (implicit ? 1 : 0);
}
}
diff --git a/src/main/org/apache/tools/ant/taskdefs/MacroInstance.java b/src/main/org/apache/tools/ant/taskdefs/MacroInstance.java
index 452b7b88f..b944a25c3 100644
--- a/src/main/org/apache/tools/ant/taskdefs/MacroInstance.java
+++ b/src/main/org/apache/tools/ant/taskdefs/MacroInstance.java
@@ -29,7 +29,7 @@ import java.util.Hashtable;
import java.util.Enumeration;
import org.apache.tools.ant.BuildException;
-import org.apache.tools.ant.DynamicConfigurator;
+import org.apache.tools.ant.DynamicAttribute;
import org.apache.tools.ant.ProjectHelper;
import org.apache.tools.ant.RuntimeConfigurable;
import org.apache.tools.ant.Target;
@@ -44,13 +44,15 @@ import org.apache.tools.ant.UnknownElement;
* the parameter values in attributes and text.
* @since Ant 1.6
*/
-public class MacroInstance extends Task implements DynamicConfigurator {
+public class MacroInstance extends Task implements DynamicAttribute, TaskContainer {
private MacroDef macroDef;
private Map map = new HashMap();
private Map nsElements = null;
private Map presentElements = new HashMap();
private Hashtable localProperties = new Hashtable();
private String text = null;
+ private String implicitTag = null;
+ private List unknownElements = new ArrayList();
/**
* Called from MacroDef.MyAntTypeDefinition#create()
@@ -79,22 +81,14 @@ public class MacroInstance extends Task implements DynamicConfigurator {
}
/**
- * Add an element.
- * @param name the name of the element
- * @return an inner Element type
- * @throws BuildException if the name is not known or if this element
- * has already been seen
+ * Method present for BC purposes.
+ * @param name not used
+ * @return nothing
+ * @deprecated
+ * @throws BuildException always
*/
public Object createDynamicElement(String name) throws BuildException {
- if (getNsElements().get(name) == null) {
- throw new BuildException("unsupported element " + name);
- }
- if (presentElements.get(name) != null) {
- throw new BuildException("Element " + name + " already present");
- }
- Element ret = new Element();
- presentElements.put(name, ret);
- return ret;
+ throw new BuildException("Not implemented any more");
}
private Map getNsElements() {
@@ -105,11 +99,43 @@ public class MacroInstance extends Task implements DynamicConfigurator {
Map.Entry entry = (Map.Entry) i.next();
nsElements.put((String) entry.getKey(),
entry.getValue());
+ MacroDef.TemplateElement te = (MacroDef.TemplateElement)
+ entry.getValue();
+ if (te.isImplicit()) {
+ implicitTag = te.getName();
+ }
}
}
return nsElements;
}
+ /**
+ * Add a unknownElement for the macro instances nested elements.
+ *
+ * @param nestedTask a nested element.
+ */
+ public void addTask(Task nestedTask) {
+ unknownElements.add(nestedTask);
+ }
+
+ private void processTasks() {
+ if (implicitTag != null) {
+ return;
+ }
+ for (Iterator i = unknownElements.iterator(); i.hasNext();) {
+ UnknownElement ue = (UnknownElement) i.next();
+ String name = ProjectHelper.extractNameFromComponentName(
+ ue.getTag()).toLowerCase(Locale.US);
+ if (getNsElements().get(name) == null) {
+ throw new BuildException("unsupported element " + name);
+ }
+ if (presentElements.get(name) != null) {
+ throw new BuildException("Element " + name + " already present");
+ }
+ presentElements.put(name, ue.getChildren());
+ }
+ }
+
/**
* Embedded element in macro instance
*/
@@ -255,9 +281,21 @@ public class MacroInstance extends Task implements DynamicConfigurator {
UnknownElement child = copy(unknownElement);
rc.addChild(child.getWrapper());
ret.addChild(child);
+ } else if (templateElement.isImplicit()) {
+ if (unknownElements.size() == 0 && !templateElement.isOptional()) {
+ throw new BuildException(
+ "Missing nested elements for implicit element "
+ + templateElement.getName());
+ }
+ for (Iterator i = unknownElements.iterator();
+ i.hasNext();) {
+ UnknownElement child = (UnknownElement) i.next();
+ rc.addChild(child.getWrapper());
+ ret.addChild(child);
+ }
} else {
- Element element = (Element) presentElements.get(tag);
- if (element == null) {
+ List list = (List) presentElements.get(tag);
+ if (list == null) {
if (!templateElement.isOptional()) {
throw new BuildException(
"Required nested element "
@@ -265,7 +303,7 @@ public class MacroInstance extends Task implements DynamicConfigurator {
}
continue;
}
- for (Iterator i = element.getUnknownElements().iterator();
+ for (Iterator i = list.iterator();
i.hasNext();) {
UnknownElement child = (UnknownElement) i.next();
rc.addChild(child.getWrapper());
@@ -283,6 +321,8 @@ public class MacroInstance extends Task implements DynamicConfigurator {
*
*/
public void execute() {
+ getNsElements();
+ processTasks();
localProperties = new Hashtable();
Set copyKeys = new HashSet(map.keySet());
for (Iterator i = macroDef.getAttributes().iterator(); i.hasNext();) {
diff --git a/src/testcases/org/apache/tools/ant/taskdefs/MacroDefTest.java b/src/testcases/org/apache/tools/ant/taskdefs/MacroDefTest.java
index baa0e84c0..793ad25c4 100644
--- a/src/testcases/org/apache/tools/ant/taskdefs/MacroDefTest.java
+++ b/src/testcases/org/apache/tools/ant/taskdefs/MacroDefTest.java
@@ -108,5 +108,25 @@ public class MacroDefTest extends BuildFileTest {
"attribute.description",
"description is hello world");
}
+ public void testImplicit() {
+ expectLog(
+ "implicit", "Before implicitIn implicitAfter implicit");
+ }
+ public void testImplicitNotOptional() {
+ expectSpecificBuildException(
+ "implicit.notoptional",
+ "Missing nested elements for implicit element implicit",
+ "Missing nested elements for implicit element implicit");
+ }
+ public void testImplicitOptional() {
+ expectLog(
+ "implicit.optional", "Before implicitAfter implicit");
+ }
+ public void testImplicitExplicit() {
+ expectSpecificBuildException(
+ "implicit.explicit",
+ "Only one element allowed when using implicit elements",
+ "Only one element allowed when using implicit elements");
+ }
}
|