Index: src/main/org/apache/tools/ant/UnknownElement.java =================================================================== --- src/main/org/apache/tools/ant/UnknownElement.java (revision 452068) +++ src/main/org/apache/tools/ant/UnknownElement.java (working copy) @@ -180,20 +180,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); } /** @@ -301,6 +296,50 @@ children.add(child); } + private void recurHandleChild( + ComponentHelper helper, Object parent, UnknownElement child) { + // MacroFragment ? + if (child.getTag().indexOf('-') != -1) { + 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 + IntrospectionHelper ih = IntrospectionHelper.getHelper( + getProject(), parent.getClass()); + 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. @@ -308,50 +347,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. * * @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()); } } @@ -528,10 +544,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( @@ -556,7 +574,7 @@ ((ProjectComponent) realChild).setLocation(child.getLocation()); } childWrapper.maybeConfigure(getProject()); - child.handleChildren(realChild, childWrapper); + child.handleChildren(realChild, null); creator.store(); return true; } Index: src/main/org/apache/tools/ant/MacroFragment.java =================================================================== --- src/main/org/apache/tools/ant/MacroFragment.java (revision 0) +++ src/main/org/apache/tools/ant/MacroFragment.java (revision 0) @@ -0,0 +1,7 @@ +package org.apache.tools.ant; + +import java.util.List; + +public interface MacroFragment { + public List getUnknownElements(UnknownElement el); +} Index: src/main/org/apache/tools/ant/taskdefs/MacroDef.java =================================================================== --- src/main/org/apache/tools/ant/taskdefs/MacroDef.java (revision 452068) +++ src/main/org/apache/tools/ant/taskdefs/MacroDef.java (working copy) @@ -40,7 +40,7 @@ * * @since Ant 1.6 */ -public class MacroDef extends AntlibDefinition { +public class MacroDef extends AntlibDefinition { private NestedSequential nestedSequential; private String name; @@ -50,6 +50,7 @@ private String textName = null; private Text text = null; private boolean hasImplicitElement = false; + private boolean fragment = false; /** * Name of the definition @@ -122,14 +123,31 @@ * @return a sequential element to be configured. */ public NestedSequential createSequential() { - if (this.nestedSequential != null) { - throw new BuildException("Only one sequential allowed"); + if (nestedSequential != null) { + throw new BuildException( + "Only one sequential or fragment allowed"); } this.nestedSequential = new NestedSequential(); return this.nestedSequential; } + /** + * This is the fragment nested element of the macrodef. + * + * @return a sequential element to be configured. + */ + public NestedSequential createFragment() { + if (nestedSequential != null) { + throw new BuildException( + "Only one sequential or fragment allowed"); + } + fragment = true; + this.nestedSequential = new NestedSequential(); + return this.nestedSequential; + } + + /** * The class corresponding to the sequential nested element. * This is a simple task container. */ @@ -329,17 +347,28 @@ */ public void execute() { if (nestedSequential == null) { - throw new BuildException("Missing sequential element"); + throw new BuildException("Missing sequential or fragment element"); } if (name == null) { throw new BuildException("Name not specified"); } + if (fragment) { + if (name.indexOf('-') == -1) { + throw new BuildException( + "fragment macro name must contain a '-'"); + } + } + name = ProjectHelper.genComponentName(getURI(), name); MyAntTypeDefinition def = new MyAntTypeDefinition(this); def.setName(name); - def.setClass(MacroInstance.class); + if (fragment) { + def.setClass(MacroFragmentTask.class); + } else { + def.setClass(MacroInstance.class); + } ComponentHelper helper = ComponentHelper.getComponentHelper( getProject()); Index: src/main/org/apache/tools/ant/taskdefs/MacroInstance.java =================================================================== --- src/main/org/apache/tools/ant/taskdefs/MacroInstance.java (revision 452068) +++ src/main/org/apache/tools/ant/taskdefs/MacroInstance.java (working copy) @@ -242,7 +242,7 @@ this.text = text; } - private UnknownElement copy(UnknownElement ue) { + protected UnknownElement copy(UnknownElement ue) { UnknownElement ret = new UnknownElement(ue.getTag()); ret.setNamespace(ue.getNamespace()); ret.setProject(getProject()); @@ -327,13 +327,7 @@ return ret; } - /** - * Execute the templates instance. - * Copies the unknown element, substitutes the attributes, - * and calls perform on the unknown element. - * - */ - public void execute() { + protected void doParams() { presentElements = new HashMap(); getNsElements(); processTasks(); @@ -386,7 +380,21 @@ "Unknown attribute" + (copyKeys.size() > 1 ? "s " : " ") + copyKeys); } - + } + + protected 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()); c.init(); @@ -401,8 +409,7 @@ throw ex; } } finally { - presentElements = null; - localAttributes = null; + clearParams(); } } } Index: src/main/org/apache/tools/ant/taskdefs/MacroFragmentTask.java =================================================================== --- src/main/org/apache/tools/ant/taskdefs/MacroFragmentTask.java (revision 0) +++ src/main/org/apache/tools/ant/taskdefs/MacroFragmentTask.java (revision 0) @@ -0,0 +1,16 @@ +package org.apache.tools.ant.taskdefs; +import java.util.List; +import org.apache.tools.ant.MacroFragment; +import org.apache.tools.ant.UnknownElement; + +public class MacroFragmentTask extends MacroInstance + implements MacroFragment { + public List getUnknownElements(UnknownElement el) { + try { + doParams(); + return copy(getMacroDef().getNestedTask()).getChildren(); + } finally { + clearParams(); + } + } +}