PR: 25633 git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@276490 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -131,6 +131,17 @@ | |||||
| </td> | </td> | ||||
| <td valign="top" align="center">No</td> | <td valign="top" align="center">No</td> | ||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <td valign="top">implicit</td> | |||||
| <td valign="top"> | |||||
| If true this nested element is implicit. This means that | |||||
| any nested elements of the macrodef instance will be placed | |||||
| in the element indicated by the name of this element. | |||||
| There can only be one element if an element is implicit. | |||||
| The default value is false. <em>since ant 1.6.2</em> | |||||
| </td> | |||||
| <td valign="top" align="center">No</td> | |||||
| </tr> | |||||
| <tr> | <tr> | ||||
| <td valign="top">description</td> | <td valign="top">description</td> | ||||
| <td valign="top"> | <td valign="top"> | ||||
| @@ -254,6 +265,45 @@ | |||||
| <linker refid="linker-libs"/> | <linker refid="linker-libs"/> | ||||
| </cc-elements> | </cc-elements> | ||||
| </call-cc> | </call-cc> | ||||
| </pre> | |||||
| </blockquote> | |||||
| <p> | |||||
| The following fragment shows <call-cc>, but this time | |||||
| using an implicit element and with the link and target.dir arguments | |||||
| having default values. | |||||
| </p> | |||||
| <blockquote> | |||||
| <pre class="code"> | |||||
| <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> | |||||
| </pre> | |||||
| </blockquote> | |||||
| <p> | |||||
| This then can be used as follows, note that <cc-elements> | |||||
| is not specified. | |||||
| </p> | |||||
| <blockquote> | |||||
| <pre class="code"> | |||||
| <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> | |||||
| </pre> | </pre> | ||||
| </blockquote> | </blockquote> | ||||
| <p> | <p> | ||||
| @@ -168,4 +168,59 @@ | |||||
| <d description="hello world"/> | <d description="hello world"/> | ||||
| </target> | </target> | ||||
| <target name="implicit"> | |||||
| <macrodef name="implicit"> | |||||
| <element name="implicit" implicit="yes"/> | |||||
| <sequential> | |||||
| <echo>Before implicit</echo> | |||||
| <implicit/> | |||||
| <echo>After implicit</echo> | |||||
| </sequential> | |||||
| </macrodef> | |||||
| <implicit> | |||||
| <echo>In implicit</echo> | |||||
| </implicit> | |||||
| </target> | |||||
| <target name="implicit.notoptional"> | |||||
| <macrodef name="implicit"> | |||||
| <element name="implicit" implicit="yes"/> | |||||
| <sequential> | |||||
| <echo>Before implicit</echo> | |||||
| <implicit/> | |||||
| <echo>After implicit</echo> | |||||
| </sequential> | |||||
| </macrodef> | |||||
| <implicit> | |||||
| </implicit> | |||||
| </target> | |||||
| <target name="implicit.optional"> | |||||
| <macrodef name="implicit"> | |||||
| <element name="implicit" optional="yes" implicit="yes"/> | |||||
| <sequential> | |||||
| <echo>Before implicit</echo> | |||||
| <implicit/> | |||||
| <echo>After implicit</echo> | |||||
| </sequential> | |||||
| </macrodef> | |||||
| <implicit> | |||||
| </implicit> | |||||
| </target> | |||||
| <target name="implicit.explicit"> | |||||
| <macrodef name="implicit"> | |||||
| <element name="explicit" optional="yes"/> | |||||
| <element name="implicit" optional="yes" implicit="yes"/> | |||||
| <sequential> | |||||
| <implicit/> | |||||
| <explicit/> | |||||
| </sequential> | |||||
| </macrodef> | |||||
| </target> | |||||
| </project> | </project> | ||||
| @@ -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; | |||||
| } | |||||
| @@ -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; | |||||
| } | |||||
| @@ -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; | |||||
| } | |||||
| @@ -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; | |||||
| } | |||||
| @@ -489,8 +489,8 @@ public final class IntrospectionHelper implements BuildListener { | |||||
| = (AttributeSetter) attributeSetters.get( | = (AttributeSetter) attributeSetters.get( | ||||
| attributeName.toLowerCase(Locale.US)); | attributeName.toLowerCase(Locale.US)); | ||||
| if (as == null) { | if (as == null) { | ||||
| if (element instanceof DynamicConfiguratorNS) { | |||||
| DynamicConfiguratorNS dc = (DynamicConfiguratorNS) element; | |||||
| if (element instanceof DynamicAttributeNS) { | |||||
| DynamicAttributeNS dc = (DynamicAttributeNS) element; | |||||
| String uriPlusPrefix = | String uriPlusPrefix = | ||||
| ProjectHelper.extractUriFromComponentName(attributeName); | ProjectHelper.extractUriFromComponentName(attributeName); | ||||
| String uri = | String uri = | ||||
| @@ -502,8 +502,8 @@ public final class IntrospectionHelper implements BuildListener { | |||||
| dc.setDynamicAttribute(uri, localName, qName, value); | dc.setDynamicAttribute(uri, localName, qName, value); | ||||
| return; | 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); | dc.setDynamicAttribute(attributeName.toLowerCase(Locale.US), value); | ||||
| return; | return; | ||||
| } else { | } else { | ||||
| @@ -611,8 +611,8 @@ public final class IntrospectionHelper implements BuildListener { | |||||
| if (nc == null) { | if (nc == null) { | ||||
| nc = createAddTypeCreator(project, parent, elementName); | 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()); | String qName = (child == null ? name : child.getQName()); | ||||
| final Object nestedElement = | final Object nestedElement = | ||||
| dc.createDynamicElement( | 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 = | final Object nestedElement = | ||||
| dc.createDynamicElement(name.toLowerCase(Locale.US)); | dc.createDynamicElement(name.toLowerCase(Locale.US)); | ||||
| if (nestedElement != null) { | if (nestedElement != null) { | ||||
| @@ -749,8 +749,8 @@ public final class IntrospectionHelper implements BuildListener { | |||||
| */ | */ | ||||
| public boolean supportsNestedElement(String elementName) { | public boolean supportsNestedElement(String elementName) { | ||||
| return nestedCreators.containsKey(elementName.toLowerCase(Locale.US)) | 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; | || addTypeMethods.size() != 0; | ||||
| } | } | ||||
| @@ -776,8 +776,8 @@ public final class IntrospectionHelper implements BuildListener { | |||||
| return ( | return ( | ||||
| nestedCreators.containsKey(name.toLowerCase(Locale.US)) | nestedCreators.containsKey(name.toLowerCase(Locale.US)) | ||||
| && (uri.equals(parentUri))) // || uri.equals(""))) | && (uri.equals(parentUri))) // || uri.equals(""))) | ||||
| || DynamicConfigurator.class.isAssignableFrom(bean) | |||||
| || DynamicConfiguratorNS.class.isAssignableFrom(bean) | |||||
| || DynamicElement.class.isAssignableFrom(bean) | |||||
| || DynamicElementNS.class.isAssignableFrom(bean) | |||||
| || addTypeMethods.size() != 0; | || addTypeMethods.size() != 0; | ||||
| } | } | ||||
| @@ -71,6 +71,13 @@ public class UnknownElement extends Task { | |||||
| this.elementName = elementName; | 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 | * Returns the name of the XML element which generated this unknown | ||||
| * element. | * element. | ||||
| @@ -46,6 +46,7 @@ public class MacroDef extends AntlibDefinition { | |||||
| private Map elements = new HashMap(); | private Map elements = new HashMap(); | ||||
| private String textName = null; | private String textName = null; | ||||
| private Text text = null; | private Text text = null; | ||||
| private boolean hasImplicitElement = false; | |||||
| /** | /** | ||||
| * Name of the definition | * Name of the definition | ||||
| @@ -254,6 +255,12 @@ public class MacroDef extends AntlibDefinition { | |||||
| "the element " + element.getName() | "the element " + element.getName() | ||||
| + " has already been specified"); | + " 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); | elements.put(element.getName(), element); | ||||
| } | } | ||||
| @@ -507,6 +514,7 @@ public class MacroDef extends AntlibDefinition { | |||||
| public static class TemplateElement { | public static class TemplateElement { | ||||
| private String name; | private String name; | ||||
| private boolean optional = false; | private boolean optional = false; | ||||
| private boolean implicit = false; | |||||
| private String description; | private String description; | ||||
| /** | /** | ||||
| @@ -546,6 +554,23 @@ public class MacroDef extends AntlibDefinition { | |||||
| return optional; | 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. | * @param desc Description of the element. | ||||
| * @since ant 1.6.1 | * @since ant 1.6.1 | ||||
| @@ -584,14 +609,15 @@ public class MacroDef extends AntlibDefinition { | |||||
| } else if (!name.equals(other.name)) { | } else if (!name.equals(other.name)) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| return optional == other.optional; | |||||
| return optional == other.optional && implicit == other.implicit; | |||||
| } | } | ||||
| /** | /** | ||||
| * @return a hash code value for this object. | * @return a hash code value for this object. | ||||
| */ | */ | ||||
| public int hashCode() { | public int hashCode() { | ||||
| return objectHashCode(name) + (optional ? 1 : 0); | |||||
| return objectHashCode(name) | |||||
| + (optional ? 1 : 0) + (implicit ? 1 : 0); | |||||
| } | } | ||||
| } | } | ||||
| @@ -29,7 +29,7 @@ import java.util.Hashtable; | |||||
| import java.util.Enumeration; | import java.util.Enumeration; | ||||
| import org.apache.tools.ant.BuildException; | 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.ProjectHelper; | ||||
| import org.apache.tools.ant.RuntimeConfigurable; | import org.apache.tools.ant.RuntimeConfigurable; | ||||
| import org.apache.tools.ant.Target; | import org.apache.tools.ant.Target; | ||||
| @@ -44,13 +44,15 @@ import org.apache.tools.ant.UnknownElement; | |||||
| * the parameter values in attributes and text. | * the parameter values in attributes and text. | ||||
| * @since Ant 1.6 | * @since Ant 1.6 | ||||
| */ | */ | ||||
| public class MacroInstance extends Task implements DynamicConfigurator { | |||||
| public class MacroInstance extends Task implements DynamicAttribute, TaskContainer { | |||||
| private MacroDef macroDef; | private MacroDef macroDef; | ||||
| private Map map = new HashMap(); | private Map map = new HashMap(); | ||||
| private Map nsElements = null; | private Map nsElements = null; | ||||
| private Map presentElements = new HashMap(); | private Map presentElements = new HashMap(); | ||||
| private Hashtable localProperties = new Hashtable(); | private Hashtable localProperties = new Hashtable(); | ||||
| private String text = null; | private String text = null; | ||||
| private String implicitTag = null; | |||||
| private List unknownElements = new ArrayList(); | |||||
| /** | /** | ||||
| * Called from MacroDef.MyAntTypeDefinition#create() | * 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 { | 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() { | private Map getNsElements() { | ||||
| @@ -105,11 +99,43 @@ public class MacroInstance extends Task implements DynamicConfigurator { | |||||
| Map.Entry entry = (Map.Entry) i.next(); | Map.Entry entry = (Map.Entry) i.next(); | ||||
| nsElements.put((String) entry.getKey(), | nsElements.put((String) entry.getKey(), | ||||
| entry.getValue()); | entry.getValue()); | ||||
| MacroDef.TemplateElement te = (MacroDef.TemplateElement) | |||||
| entry.getValue(); | |||||
| if (te.isImplicit()) { | |||||
| implicitTag = te.getName(); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| return nsElements; | 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 | * Embedded element in macro instance | ||||
| */ | */ | ||||
| @@ -255,9 +281,21 @@ public class MacroInstance extends Task implements DynamicConfigurator { | |||||
| UnknownElement child = copy(unknownElement); | UnknownElement child = copy(unknownElement); | ||||
| rc.addChild(child.getWrapper()); | rc.addChild(child.getWrapper()); | ||||
| ret.addChild(child); | 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 { | } else { | ||||
| Element element = (Element) presentElements.get(tag); | |||||
| if (element == null) { | |||||
| List list = (List) presentElements.get(tag); | |||||
| if (list == null) { | |||||
| if (!templateElement.isOptional()) { | if (!templateElement.isOptional()) { | ||||
| throw new BuildException( | throw new BuildException( | ||||
| "Required nested element " | "Required nested element " | ||||
| @@ -265,7 +303,7 @@ public class MacroInstance extends Task implements DynamicConfigurator { | |||||
| } | } | ||||
| continue; | continue; | ||||
| } | } | ||||
| for (Iterator i = element.getUnknownElements().iterator(); | |||||
| for (Iterator i = list.iterator(); | |||||
| i.hasNext();) { | i.hasNext();) { | ||||
| UnknownElement child = (UnknownElement) i.next(); | UnknownElement child = (UnknownElement) i.next(); | ||||
| rc.addChild(child.getWrapper()); | rc.addChild(child.getWrapper()); | ||||
| @@ -283,6 +321,8 @@ public class MacroInstance extends Task implements DynamicConfigurator { | |||||
| * | * | ||||
| */ | */ | ||||
| public void execute() { | public void execute() { | ||||
| getNsElements(); | |||||
| processTasks(); | |||||
| localProperties = new Hashtable(); | localProperties = new Hashtable(); | ||||
| Set copyKeys = new HashSet(map.keySet()); | Set copyKeys = new HashSet(map.keySet()); | ||||
| for (Iterator i = macroDef.getAttributes().iterator(); i.hasNext();) { | for (Iterator i = macroDef.getAttributes().iterator(); i.hasNext();) { | ||||
| @@ -108,5 +108,25 @@ public class MacroDefTest extends BuildFileTest { | |||||
| "attribute.description", | "attribute.description", | ||||
| "description is hello world"); | "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"); | |||||
| } | |||||
| } | } | ||||