--- src/tests/antunit/taskdefs/fragmentdef-test.xml (revision 0) +++ src/tests/antunit/taskdefs/fragmentdef-test.xml (revision 0) @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + native --- src/main/org/apache/tools/ant/IntrospectionHelper.java (revision 572578) +++ src/main/org/apache/tools/ant/IntrospectionHelper.java (working copy) @@ -647,6 +647,19 @@ if (isDynamic() || addTypeMethods.size() > 0) { return true; } + return supportsReflectElement(parentUri, elementName); + } + + /** + * Check if this element supports a nested element from refection. + * + * @param parentUri the uri of the parent + * @param elementName the name of the nested element being checked + * + * @return true if the given nested element is supported + */ + public boolean supportsReflectElement( + String parentUri, String elementName) { String name = ProjectHelper.extractNameFromComponentName(elementName); if (!nestedCreators.containsKey(name.toLowerCase(Locale.US))) { return false; --- src/main/org/apache/tools/ant/UnknownElement.java (revision 572578) +++ 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,51 @@ 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()) + && 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 +355,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 +552,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 +582,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/MacroDef.java (revision 572578) +++ 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,8 +50,17 @@ private String textName = null; private Text text = null; private boolean hasImplicitElement = false; + private boolean fragment = false; /** + * Called by the fragmentdef subclass. + * @param fragment the value to use (true). + */ + protected void setFragment(boolean fragment) { + this.fragment = true; + } + + /** * Name of the definition * @param name the name of the definition */ @@ -122,8 +131,9 @@ * @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 allowed"); } this.nestedSequential = new NestedSequential(); return this.nestedSequential; @@ -300,17 +310,20 @@ */ 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"); } - 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()); --- src/main/org/apache/tools/ant/taskdefs/MacroInstance.java (revision 572578) +++ src/main/org/apache/tools/ant/taskdefs/MacroInstance.java (working copy) @@ -242,7 +242,12 @@ this.text = text; } - private UnknownElement copy(UnknownElement ue) { + /** + * Copy an unknown element, substituting in macro attributes. + * @param ue the unknown element to replace. + * @return the copied unknown element. + */ + protected UnknownElement copy(UnknownElement ue) { UnknownElement ret = new UnknownElement(ue.getTag()); ret.setNamespace(ue.getNamespace()); ret.setProject(getProject()); @@ -327,13 +332,8 @@ 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 */ + protected void doParams() { presentElements = new HashMap(); getNsElements(); processTasks(); @@ -384,7 +384,22 @@ "Unknown attribute" + (copyKeys.size() > 1 ? "s " : " ") + copyKeys); } + } + /** Clear the parameters */ + 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(); @@ -399,8 +414,7 @@ throw ex; } } finally { - presentElements = null; - localAttributes = null; + clearParams(); } } } --- src/main/org/apache/tools/ant/taskdefs/FragmentDef.java (revision 0) +++ src/main/org/apache/tools/ant/taskdefs/FragmentDef.java (revision 0) @@ -0,0 +1,30 @@ +/* + * 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.taskdefs; + +/** + * The fragmentdef task. + * This is the same as macrodef, exception that the + * protected attribute fragment is set to true. + */ +public class FragmentDef extends MacroDef { + { + setFragment(true); + } +} --- 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,43 @@ +/* + * 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.taskdefs; + +import java.util.List; +import org.apache.tools.ant.MacroFragment; +import org.apache.tools.ant.UnknownElement; + +/** + * A sub-class of a macroinstance that can be used (nearly) anywhere + * in a build file. + */ +public class MacroFragmentTask extends MacroInstance implements MacroFragment { + /** + * 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()).getChildren(); + } finally { + clearParams(); + } + } +} --- src/main/org/apache/tools/ant/taskdefs/defaults.properties (revision 572578) +++ src/main/org/apache/tools/ant/taskdefs/defaults.properties (working copy) @@ -32,6 +32,7 @@ fail=org.apache.tools.ant.taskdefs.Exit filter=org.apache.tools.ant.taskdefs.Filter fixcrlf=org.apache.tools.ant.taskdefs.FixCRLF +fragmentdef=org.apache.tools.ant.taskdefs.FragmentDef genkey=org.apache.tools.ant.taskdefs.GenerateKey get=org.apache.tools.ant.taskdefs.Get gunzip=org.apache.tools.ant.taskdefs.GUnzip --- docs/manual/CoreTasks/fragmentdef.html (revision 0) +++ docs/manual/CoreTasks/fragmentdef.html (revision 0) @@ -0,0 +1,63 @@ + + + + + + + FragmentDef Task + + + + +

FragmentDef

+

Description

+

+ This defines a new task using a <sequential> + nested list of elements. This task is similar to + <macrodef> except that + arbitary element sequences may be placed within tasks or types. +

+

+ The parameters and nested elements are same as + <macrodef> - see that task for + them. This description will just contain examples. +

Examples

+

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

+
+
+<fragmentdef name="sourcefiles">
+   <sequential>
+     <fileset dir="src/main/java" includes="**/*.java">
+     <fileset dir="src/main/resources"/>
+   </sequential>
+</fragmentdef>
+
+<copy todir="allsource">
+   <sourcefiles/>
+</copy>
+
+<m:remote-copy remotedir="wr0t@billy:backups">
+   <sourcefiles/>
+</m:remote-copy>
+
+
+ + --- docs/manual/coretasklist.html (revision 572578) +++ docs/manual/coretasklist.html (working copy) @@ -72,6 +72,7 @@ Fail
Filter
FixCRLF
+FragmentDef
GenKey
Get
GUnzip