Browse Source

add implicit element to macrodef

PR:  25633


git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@276490 13f79535-47bb-0310-9956-ffa450edef68
master
Peter Reilly 21 years ago
parent
commit
278074659b
11 changed files with 379 additions and 33 deletions
  1. +50
    -0
      docs/manual/CoreTasks/macrodef.html
  2. +55
    -0
      src/etc/testcases/taskdefs/macrodef.xml
  3. +37
    -0
      src/main/org/apache/tools/ant/DynamicAttribute.java
  4. +40
    -0
      src/main/org/apache/tools/ant/DynamicAttributeNS.java
  5. +35
    -0
      src/main/org/apache/tools/ant/DynamicElement.java
  6. +36
    -0
      src/main/org/apache/tools/ant/DynamicElementNS.java
  7. +12
    -12
      src/main/org/apache/tools/ant/IntrospectionHelper.java
  8. +7
    -0
      src/main/org/apache/tools/ant/UnknownElement.java
  9. +28
    -2
      src/main/org/apache/tools/ant/taskdefs/MacroDef.java
  10. +59
    -19
      src/main/org/apache/tools/ant/taskdefs/MacroInstance.java
  11. +20
    -0
      src/testcases/org/apache/tools/ant/taskdefs/MacroDefTest.java

+ 50
- 0
docs/manual/CoreTasks/macrodef.html View File

@@ -131,6 +131,17 @@
</td>
<td valign="top" align="center">No</td>
</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>
<td valign="top">description</td>
<td valign="top">
@@ -254,6 +265,45 @@
&lt;linker refid="linker-libs"/&gt;
&lt;/cc-elements&gt;
&lt;/call-cc&gt;
</pre>
</blockquote>
<p>
The following fragment shows &lt;call-cc&gt;, but this time
using an implicit element and with the link and target.dir arguments
having default values.
</p>
<blockquote>
<pre class="code">
&lt;macrodef name="call-cc"&gt;
&lt;attribute name="target"/&gt;
&lt;attribute name="link" default="executable"/&gt;
&lt;attribute name="target.dir" default="${build.bin.dir}"/&gt;
&lt;element name="cc-elements" implicit="yes"/&gt;
&lt;sequential&gt;
&lt;mkdir dir="${obj.dir}/@{target}"/&gt;
&lt;mkdir dir="@{target.dir}"/&gt;
&lt;cc link="@{link}" objdir="${obj.dir}/@{target}"
outfile="@{target.dir}/@{target}"&gt;
&lt;compiler refid="compiler.options"/&gt;
&lt;cc-elements/&gt;
&lt;/cc&gt;
&lt;/sequential&gt;
&lt;/macrodef&gt;
</pre>
</blockquote>
<p>
This then can be used as follows, note that &lt;cc-elements&gt;
is not specified.
</p>
<blockquote>
<pre class="code">
&lt;call-cc target="unittests"/&gt;
&lt;includepath location="${gen.dir}"/&gt;
&lt;includepath location="test"/&gt;
&lt;fileset dir="test/unittest" includes = "**/*.cpp"/&gt;
&lt;fileset dir="${gen.dir}" includes = "*.cpp"/&gt;
&lt;linker refid="linker-libs"/&gt;
&lt;/call-cc&gt;
</pre>
</blockquote>
<p>


+ 55
- 0
src/etc/testcases/taskdefs/macrodef.xml View File

@@ -168,4 +168,59 @@
<d description="hello world"/>
</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>

+ 37
- 0
src/main/org/apache/tools/ant/DynamicAttribute.java View File

@@ -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;

}

+ 40
- 0
src/main/org/apache/tools/ant/DynamicAttributeNS.java View File

@@ -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;

}

+ 35
- 0
src/main/org/apache/tools/ant/DynamicElement.java View File

@@ -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;
}

+ 36
- 0
src/main/org/apache/tools/ant/DynamicElementNS.java View File

@@ -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;
}

+ 12
- 12
src/main/org/apache/tools/ant/IntrospectionHelper.java View File

@@ -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;
}



+ 7
- 0
src/main/org/apache/tools/ant/UnknownElement.java View File

@@ -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.


+ 28
- 2
src/main/org/apache/tools/ant/taskdefs/MacroDef.java View File

@@ -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);
}
}



+ 59
- 19
src/main/org/apache/tools/ant/taskdefs/MacroInstance.java View File

@@ -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();) {


+ 20
- 0
src/testcases/org/apache/tools/ant/taskdefs/MacroDefTest.java View File

@@ -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");
}
}


Loading…
Cancel
Save