--- src/tests/antunit/taskdefs/macrodef-element-test.xml (revision 0) +++ src/tests/antunit/taskdefs/macrodef-element-test.xml (revision 0) @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + --- src/main/org/apache/tools/ant/UnknownElement.java (revision 575729) +++ src/main/org/apache/tools/ant/UnknownElement.java (working copy) @@ -182,20 +182,15 @@ if (getWrapper().getId() != null) { this.getOwningTarget().replaceChild(this, (Task) realThing); } - } + } - - // configure attributes of the object and it's children. If it is - // a task container, defer the configuration till the task container - // attempts to use the task - if (task != null) { task.maybeConfigure(); } else { getWrapper().maybeConfigure(getProject()); } - handleChildren(realThing, getWrapper()); + handleChildren(realThing, null); } /** @@ -308,6 +303,52 @@ children.add(child); } + private void recurHandleChild( + ComponentHelper helper, Object parent, UnknownElement child) { + IntrospectionHelper ih = IntrospectionHelper.getHelper( + getProject(), parent.getClass()); + + if (!ih.supportsReflectElement(getNamespace(), child.getComponentName()) + &&!ih.isContainer() + && helper.getDefinition(child.getComponentName()) != null) { + Class componentClass = helper.getComponentClass( + child.getComponentName()); + if ((componentClass != null) + && (MacroFragment.class.isAssignableFrom(componentClass))) { + child.maybeConfigure(); + + MacroFragment macroFragment = (MacroFragment) child.realThing; + + List replaced = macroFragment.getUnknownElements(child); + for (Iterator i = replaced.iterator(); i.hasNext();) { + recurHandleChild( + helper, parent, (UnknownElement) i.next()); + } + return; + } + } + // not a macro fragment - a "Normal" element + try { + if (!handleChild( + getNamespace(), ih, parent, child)) { + if (!(parent instanceof TaskContainer)) { + ih.throwNotSupported(getProject(), parent, + child.getTag()); + } else { + // a task container - anything could happen + // - just add the child to the container + TaskContainer container = (TaskContainer) parent; + container.addTask(child); + } + } + } catch (UnsupportedElementException ex) { + throw new BuildException( + getWrapper().getElementTag() + + " doesn't support the nested \"" + ex.getElement() + + "\" element.", ex); + } + } + /** * Creates child elements, creates children of the children * (recursively), and sets attributes of the child elements. @@ -315,50 +356,27 @@ * @param parent The configured object for the parent. * Must not be null. * - * @param parentWrapper The wrapper containing child wrappers - * to be configured. Must not be null - * if there are any children. + * @param notUsed Not used.(kept for BC reasons) * * @exception BuildException if the children cannot be configured. */ protected void handleChildren( Object parent, - RuntimeConfigurable parentWrapper) + RuntimeConfigurable notUsed) throws BuildException { + if (children == null) { + return; + } + + ComponentHelper helper = ComponentHelper.getComponentHelper( + getProject()); + if (parent instanceof TypeAdapter) { parent = ((TypeAdapter) parent).getProxy(); } - String parentUri = getNamespace(); - Class parentClass = parent.getClass(); - IntrospectionHelper ih = IntrospectionHelper.getHelper(getProject(), parentClass); - - - if (children != null) { - Iterator it = children.iterator(); - for (int i = 0; it.hasNext(); i++) { - RuntimeConfigurable childWrapper = parentWrapper.getChild(i); - UnknownElement child = (UnknownElement) it.next(); - try { - if (!handleChild( - parentUri, ih, parent, child, childWrapper)) { - if (!(parent instanceof TaskContainer)) { - ih.throwNotSupported(getProject(), parent, - child.getTag()); - } else { - // a task container - anything could happen - just add the - // child to the container - TaskContainer container = (TaskContainer) parent; - container.addTask(child); - } - } - } catch (UnsupportedElementException ex) { - throw new BuildException( - parentWrapper.getElementTag() - + " doesn't support the nested \"" + ex.getElement() - + "\" element.", ex); - } - } + for (Iterator i = children.iterator(); i.hasNext();) { + recurHandleChild(helper, parent, (UnknownElement) i.next()); } } @@ -535,10 +553,12 @@ private boolean handleChild( String parentUri, IntrospectionHelper ih, - Object parent, UnknownElement child, - RuntimeConfigurable childWrapper) { + Object parent, UnknownElement child) { + RuntimeConfigurable childWrapper = child.getWrapper(); + String childName = ProjectHelper.genComponentName( child.getNamespace(), child.getTag()); + if (ih.supportsNestedElement(parentUri, childName)) { IntrospectionHelper.Creator creator = ih.getElementCreator( @@ -563,7 +583,7 @@ ((ProjectComponent) realChild).setLocation(child.getLocation()); } childWrapper.maybeConfigure(getProject()); - child.handleChildren(realChild, childWrapper); + child.handleChildren(realChild, null); creator.store(); return true; } --- src/main/org/apache/tools/ant/MacroFragment.java (revision 0) +++ src/main/org/apache/tools/ant/MacroFragment.java (revision 0) @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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; + +import java.util.List; + +/** + * An interface for a task/type that can be used to + * inject a list of unknown elements into a build file. + */ +public interface MacroFragment { + /** + * Convert the unknown element into a list of ues. + * @param el the unknown element to convert. + * @return the list of unknown elements. + */ + List getUnknownElements(UnknownElement el); +} --- src/main/org/apache/tools/ant/taskdefs/MacroInstance.java (revision 575729) +++ src/main/org/apache/tools/ant/taskdefs/MacroInstance.java (working copy) @@ -32,6 +32,7 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DynamicAttribute; import org.apache.tools.ant.ProjectHelper; +import org.apache.tools.ant.MacroFragment; import org.apache.tools.ant.RuntimeConfigurable; import org.apache.tools.ant.Target; import org.apache.tools.ant.Task; @@ -45,7 +46,8 @@ * the parameter values in attributes and text. * @since Ant 1.6 */ -public class MacroInstance extends Task implements DynamicAttribute, TaskContainer { +public class MacroInstance extends Task + implements DynamicAttribute, TaskContainer, MacroFragment { private MacroDef macroDef; private Map map = new HashMap(); private Map nsElements = null; @@ -72,6 +74,20 @@ } /** + * Get the unknown elements to inject into the build document. + * @param el the unknown element this is this fragment. + * @return the replacement list of unknown elements. + */ + public List getUnknownElements(UnknownElement el) { + try { + doParams(); + return copy(getMacroDef().getNestedTask(), false).getChildren(); + } finally { + clearParams(); + } + } + + /** * A parameter name value pair as a xml attribute. * * @param name the name of the attribute @@ -93,21 +109,22 @@ } private Map getNsElements() { - if (nsElements == null) { - nsElements = new HashMap(); - for (Iterator i = macroDef.getElements().entrySet().iterator(); - i.hasNext();) { - 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; + } + + private void doNsElements() { + nsElements = new HashMap(); + for (Iterator i = macroDef.getElements().entrySet().iterator(); + i.hasNext();) { + 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; } /** @@ -119,7 +136,14 @@ unknownElements.add(nestedTask); } - private void processTasks() { + /** + * process the nested elements of this macro instance. + * Ensure that the correspond to the elements definitions + * in the macrodef. + * If the there is one nested elemtent of implicit type, then + * there is no processsing. + */ + private void processNestedElements() { if (implicitTag != null) { return; } @@ -242,7 +266,12 @@ this.text = text; } - private UnknownElement copy(UnknownElement ue, boolean nested) { + /** + * Copy an unknown element, substituting in macro attributes. + * @param ue the unknown element to replace. + * @return the copied unknown element. + */ + private UnknownElement copy(UnknownElement ue, boolean nested) { UnknownElement ret = new UnknownElement(ue.getTag()); ret.setNamespace(ue.getNamespace()); ret.setProject(getProject()); @@ -329,16 +358,11 @@ return ret; } - /** - * Execute the templates instance. - * Copies the unknown element, substitutes the attributes, - * and calls perform on the unknown element. - * - */ - public void execute() { + /** setup parameters */ + private void doParams() { presentElements = new HashMap(); - getNsElements(); - processTasks(); + doNsElements(); + processNestedElements(); localAttributes = new Hashtable(); Set copyKeys = new HashSet(map.keySet()); for (Iterator i = macroDef.getAttributes().iterator(); i.hasNext();) { @@ -386,7 +410,22 @@ "Unknown attribute" + (copyKeys.size() > 1 ? "s " : " ") + copyKeys); } + } + /** Clear the parameters */ + private void clearParams() { + presentElements = null; + localAttributes = null; + } + + /** + * Execute the templates instance. + * Copies the unknown element, substitutes the attributes, + * and calls perform on the unknown element. + * + */ + public void execute() { + doParams(); // need to set the project on unknown element UnknownElement c = copy(macroDef.getNestedTask(), false); c.init(); @@ -401,8 +440,7 @@ throw ex; } } finally { - presentElements = null; - localAttributes = null; + clearParams(); } } } --- src/etc/checkstyle/checkstyle-config (revision 575729) +++ src/etc/checkstyle/checkstyle-config (working copy) @@ -80,8 +80,8 @@ - - + + --- docs/manual/CoreTasks/macrodef.html (revision 575729) +++ docs/manual/CoreTasks/macrodef.html (working copy) @@ -27,20 +27,37 @@

MacroDef

Description

- This defines a new task using a <sequential> - nested task as a template. Nested elements <attribute> and - <element> are used to specify attributes and elements of - the new task. These get substituted into the <sequential> - task when the new task is run. + Since Ant 1.6.
+ This defines a new element that may be used to replace a sequence + of elements and thus allow reuse of the elements in other + parts of the build document. + + This defines a new element tag using a <sequential> + nested task as a template. + Nested elements <attribute> and + <element> are used to specify attributes + and elements of the new task. These get substituted into the + <sequential> + task when the new element tag is evalulated.

-

Note

-

- You can also use prior defined attributes for default-values in - other attributes. See the examples. -

-

- since Ant 1.6 -

+ + + + + + + + + + +
Note: + You can also use prior defined attributes for default-values + in other attributes. See the examples. +
Note: + Since Ant 1.8, macrodef defined elements can replace + arbitary nested elements and not just tasks. +
+

Parameters

@@ -370,7 +387,27 @@ <test one="test"/> +

+ The following defines two filesets and then places them in + two different copy tasks. +

+
+
+<macrodef name="sourcefiles">
+   <sequential>
+     <fileset dir="src/main/java" includes="**/*.java">
+     <fileset dir="src/main/resources"/>
+   </sequential>
+</macrodef>
 
+<copy todir="allsource">
+   <sourcefiles/>
+</copy>
 
+<m:remote-copy remotedir="wr0t@billy:backups">
+   <sourcefiles/>
+</m:remote-copy>
+
+