nested elements of types/tasks use the same NS uri as the task/type. also cleanup macrodef attribute handling git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@275639 13f79535-47bb-0310-9956-ffa450edef68master
@@ -133,9 +133,9 @@ | |||||
<sequential> | <sequential> | ||||
<current:if> | <current:if> | ||||
<current:isallowed test="${action}"/> | <current:isallowed test="${action}"/> | ||||
<then> | |||||
<do/> | |||||
</then> | |||||
<current:then> | |||||
<current:do/> | |||||
</current:then> | |||||
</current:if> | </current:if> | ||||
</sequential> | </sequential> | ||||
</macrodef> | </macrodef> | ||||
@@ -642,6 +642,52 @@ public final class IntrospectionHelper implements BuildListener { | |||||
return nc; | return nc; | ||||
} | } | ||||
private NestedCreator getNestedCreator( | |||||
Project project, String parentUri, Object parent, | |||||
String elementName) throws BuildException { | |||||
String uri = ProjectHelper.extractUriFromComponentName(elementName); | |||||
String name = ProjectHelper.extractNameFromComponentName(elementName); | |||||
NestedCreator nc = null; | |||||
if (uri.equals(parentUri)) { // || uri.equals("")) { | |||||
nc = (NestedCreator) nestedCreators.get( | |||||
name.toLowerCase(Locale.US)); | |||||
} | |||||
if (nc == null) { | |||||
nc = createAddTypeCreator(project, parent, elementName); | |||||
} | |||||
if (nc == null && parent instanceof DynamicConfigurator) { | |||||
DynamicConfigurator dc = (DynamicConfigurator) parent; | |||||
final Object nestedElement = dc.createDynamicElement(elementName); | |||||
if (nestedElement != null) { | |||||
nc = new NestedCreator() { | |||||
public boolean isPolyMorphic() { | |||||
return false; | |||||
} | |||||
public Class getElementClass() { | |||||
return null; | |||||
} | |||||
public Object getRealObject() { | |||||
return null; | |||||
} | |||||
public Object create( | |||||
Project project, Object parent, Object ignore) { | |||||
return nestedElement; | |||||
} | |||||
public void store(Object parent, Object child) { | |||||
} | |||||
}; | |||||
} | |||||
} | |||||
if (nc == null) { | |||||
throwNotSupported(project, parent, elementName); | |||||
} | |||||
return nc; | |||||
} | |||||
/** | /** | ||||
* Creates a named nested element. Depending on the results of the | * Creates a named nested element. Depending on the results of the | ||||
* initial introspection, either a method in the given parent instance | * initial introspection, either a method in the given parent instance | ||||
@@ -692,6 +738,7 @@ public final class IntrospectionHelper implements BuildListener { | |||||
* for an element of a parent. | * for an element of a parent. | ||||
* | * | ||||
* @param project Project to which the parent object belongs. | * @param project Project to which the parent object belongs. | ||||
* @param parentUri The namespace uri of the parent object. | |||||
* @param parent Parent object used to create the creator object to | * @param parent Parent object used to create the creator object to | ||||
* create and store and instance of a subelement. | * create and store and instance of a subelement. | ||||
* @param elementName Name of the element to create an instance of. | * @param elementName Name of the element to create an instance of. | ||||
@@ -699,8 +746,9 @@ public final class IntrospectionHelper implements BuildListener { | |||||
*/ | */ | ||||
public Creator getElementCreator( | public Creator getElementCreator( | ||||
Project project, Object parent, String elementName) { | |||||
NestedCreator nc = getNestedCreator(project, parent, elementName); | |||||
Project project, String parentUri, Object parent, String elementName) { | |||||
NestedCreator nc = getNestedCreator( | |||||
project, parentUri, parent, elementName); | |||||
return new Creator(project, parent, nc); | return new Creator(project, parent, nc); | ||||
} | } | ||||
@@ -718,6 +766,26 @@ public final class IntrospectionHelper implements BuildListener { | |||||
|| addTypeMethods.size() != 0; | || addTypeMethods.size() != 0; | ||||
} | } | ||||
/** | |||||
* Indicate if this element supports a nested element of the | |||||
* given name. | |||||
* | |||||
* @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 supportsNestedElement(String parentUri, String elementName) { | |||||
String uri = ProjectHelper.extractUriFromComponentName(elementName); | |||||
String name = ProjectHelper.extractNameFromComponentName(elementName); | |||||
return ( | |||||
nestedCreators.containsKey(name.toLowerCase(Locale.US)) | |||||
&& (uri.equals(parentUri))) // || uri.equals(""))) | |||||
|| DynamicConfigurator.class.isAssignableFrom(bean) | |||||
|| addTypeMethods.size() != 0; | |||||
} | |||||
/** | /** | ||||
* Stores a named nested element using a storage method determined | * Stores a named nested element using a storage method determined | ||||
* by the initial introspection. If no appropriate storage method | * by the initial introspection. If no appropriate storage method | ||||
@@ -525,12 +525,29 @@ public class ProjectHelper { | |||||
* @return The uri or "" if not present | * @return The uri or "" if not present | ||||
*/ | */ | ||||
public static String extractUriFromComponentName(String componentName) { | public static String extractUriFromComponentName(String componentName) { | ||||
if (componentName == null) { | |||||
return ""; | |||||
} | |||||
int index = componentName.lastIndexOf(':'); | int index = componentName.lastIndexOf(':'); | ||||
if (index == -1) { | if (index == -1) { | ||||
return ""; | return ""; | ||||
} | } | ||||
return componentName.substring(0, index); | return componentName.substring(0, index); | ||||
} | } | ||||
/** | |||||
* extract the element name from a component name | |||||
* | |||||
* @param componentName The stringified form for {uri, name} | |||||
* @return The element name of the component | |||||
*/ | |||||
public static String extractNameFromComponentName(String componentName) { | |||||
int index = componentName.lastIndexOf(':'); | |||||
if (index == -1) { | |||||
return componentName; | |||||
} | |||||
return componentName.substring(index+1); | |||||
} | |||||
/** | /** | ||||
* Add location to build exception. | * Add location to build exception. | ||||
@@ -493,7 +493,7 @@ public abstract class Task extends ProjectComponent { | |||||
* | * | ||||
* @return the type of task | * @return the type of task | ||||
*/ | */ | ||||
protected String getTaskType() { | |||||
public String getTaskType() { | |||||
return taskType; | return taskType; | ||||
} | } | ||||
@@ -336,13 +336,15 @@ public class UnknownElement extends Task { | |||||
* | * | ||||
* @exception BuildException if the children cannot be configured. | * @exception BuildException if the children cannot be configured. | ||||
*/ | */ | ||||
protected void handleChildren(Object parent, | |||||
RuntimeConfigurable parentWrapper) | |||||
protected void handleChildren( | |||||
Object parent, | |||||
RuntimeConfigurable parentWrapper) | |||||
throws BuildException { | throws BuildException { | ||||
if (parent instanceof TypeAdapter) { | if (parent instanceof TypeAdapter) { | ||||
parent = ((TypeAdapter) parent).getProxy(); | parent = ((TypeAdapter) parent).getProxy(); | ||||
} | } | ||||
String parentUri = getNamespace(); | |||||
Class parentClass = parent.getClass(); | Class parentClass = parent.getClass(); | ||||
IntrospectionHelper ih = IntrospectionHelper.getHelper(parentClass); | IntrospectionHelper ih = IntrospectionHelper.getHelper(parentClass); | ||||
@@ -352,8 +354,8 @@ public class UnknownElement extends Task { | |||||
for (int i = 0; it.hasNext(); i++) { | for (int i = 0; it.hasNext(); i++) { | ||||
RuntimeConfigurable childWrapper = parentWrapper.getChild(i); | RuntimeConfigurable childWrapper = parentWrapper.getChild(i); | ||||
UnknownElement child = (UnknownElement) it.next(); | UnknownElement child = (UnknownElement) it.next(); | ||||
if (!handleChild(ih, parent, child, | |||||
childWrapper)) { | |||||
if (!handleChild( | |||||
parentUri, ih, parent, child, childWrapper)) { | |||||
if (!(parent instanceof TaskContainer)) { | if (!(parent instanceof TaskContainer)) { | ||||
ih.throwNotSupported(getProject(), parent, | ih.throwNotSupported(getProject(), parent, | ||||
child.getTag()); | child.getTag()); | ||||
@@ -548,14 +550,16 @@ public class UnknownElement extends Task { | |||||
* | * | ||||
* @return whether the creation has been successful | * @return whether the creation has been successful | ||||
*/ | */ | ||||
private boolean handleChild(IntrospectionHelper ih, | |||||
Object parent, UnknownElement child, | |||||
RuntimeConfigurable childWrapper) { | |||||
private boolean handleChild( | |||||
String parentUri, | |||||
IntrospectionHelper ih, | |||||
Object parent, UnknownElement child, | |||||
RuntimeConfigurable childWrapper) { | |||||
String childName = ProjectHelper.genComponentName( | String childName = ProjectHelper.genComponentName( | ||||
child.getNamespace(), child.getTag()); | child.getNamespace(), child.getTag()); | ||||
if (ih.supportsNestedElement(childName)) { | |||||
if (ih.supportsNestedElement(parentUri, childName)) { | |||||
IntrospectionHelper.Creator creator = | IntrospectionHelper.Creator creator = | ||||
ih.getElementCreator(getProject(), parent, childName); | |||||
ih.getElementCreator(getProject(), parentUri, parent, childName); | |||||
creator.setPolyType(childWrapper.getPolyType()); | creator.setPolyType(childWrapper.getPolyType()); | ||||
Object realChild = creator.create(); | Object realChild = creator.create(); | ||||
if (realChild instanceof PreSetDef.PreSetDefinition) { | if (realChild instanceof PreSetDef.PreSetDefinition) { | ||||
@@ -939,8 +939,9 @@ public class ProjectHelper2 extends ProjectHelper { | |||||
UnknownElement task = new UnknownElement(tag); | UnknownElement task = new UnknownElement(tag); | ||||
task.setProject(context.getProject()); | task.setProject(context.getProject()); | ||||
task.setNamespace(uri); | task.setNamespace(uri); | ||||
//XXX task.setTaskType(qname); | |||||
task.setQName(qname); | task.setQName(qname); | ||||
task.setTaskType( | |||||
ProjectHelper.genComponentName(task.getNamespace(), tag)); | |||||
task.setTaskName(qname); | task.setTaskName(qname); | ||||
Location location = new Location(context.getLocator().getSystemId(), | Location location = new Location(context.getLocator().getSystemId(), | ||||
@@ -84,8 +84,10 @@ import org.apache.tools.ant.UnknownElement; | |||||
public class MacroInstance extends Task implements DynamicConfigurator { | public class MacroInstance extends Task implements DynamicConfigurator { | ||||
private MacroDef macroDef; | private MacroDef macroDef; | ||||
private Map map = new HashMap(); | private Map map = new HashMap(); | ||||
private Map elements = new HashMap(); | |||||
private Map nsElements = null; | |||||
private Map presentElements = new HashMap(); | |||||
private Hashtable localProperties = new Hashtable(); | private Hashtable localProperties = new Hashtable(); | ||||
/** | /** | ||||
* Called from MacroDef.MyAntTypeDefinition#create() | * Called from MacroDef.MyAntTypeDefinition#create() | ||||
@@ -114,17 +116,33 @@ public class MacroInstance extends Task implements DynamicConfigurator { | |||||
* has already been seen | * has already been seen | ||||
*/ | */ | ||||
public Object createDynamicElement(String name) throws BuildException { | public Object createDynamicElement(String name) throws BuildException { | ||||
if (macroDef.getElements().get(name) == null) { | |||||
if (getNsElements().get(name) == null) { | |||||
throw new BuildException("unsupported element " + name); | throw new BuildException("unsupported element " + name); | ||||
} | } | ||||
if (elements.get(name) != null) { | |||||
if (presentElements.get(name) != null) { | |||||
throw new BuildException("Element " + name + " already present"); | throw new BuildException("Element " + name + " already present"); | ||||
} | } | ||||
Element ret = new Element(); | Element ret = new Element(); | ||||
elements.put(name, ret); | |||||
presentElements.put(name, ret); | |||||
return ret; | return ret; | ||||
} | } | ||||
private Map getNsElements() { | |||||
if (nsElements == null) { | |||||
nsElements = new HashMap(); | |||||
String myUri = ProjectHelper.extractUriFromComponentName( | |||||
getTaskType()); | |||||
for (Iterator i = macroDef.getElements().entrySet().iterator(); | |||||
i.hasNext();) { | |||||
Map.Entry entry = (Map.Entry) i.next(); | |||||
nsElements.put(ProjectHelper.genComponentName( | |||||
myUri, (String) entry.getKey()), | |||||
entry.getValue()); | |||||
} | |||||
} | |||||
return nsElements; | |||||
} | |||||
/** | /** | ||||
* Embedded element in macro instance | * Embedded element in macro instance | ||||
*/ | */ | ||||
@@ -148,18 +166,38 @@ public class MacroInstance extends Task implements DynamicConfigurator { | |||||
} | } | ||||
} | } | ||||
private static final int STATE_NORMAL = 0; | |||||
private static final int STATE_EXPECT_BRACKET = 1; | |||||
private static final int STATE_EXPECT_NAME = 2; | |||||
private String macroSubs(String s, Map macroMapping) { | private String macroSubs(String s, Map macroMapping) { | ||||
StringBuffer ret = new StringBuffer(); | StringBuffer ret = new StringBuffer(); | ||||
StringBuffer macroName = new StringBuffer(); | |||||
StringBuffer macroName = null; | |||||
boolean inMacro = false; | boolean inMacro = false; | ||||
int state = STATE_NORMAL; | |||||
for (int i = 0; i < s.length(); ++i) { | for (int i = 0; i < s.length(); ++i) { | ||||
if (s.charAt(i) == '$') { | |||||
inMacro = true; | |||||
} else { | |||||
if (inMacro) { | |||||
if (s.charAt(i) == '{') { | |||||
continue; | |||||
} else if (s.charAt(i) == '}') { | |||||
char ch = s.charAt(i); | |||||
switch (state) { | |||||
case STATE_NORMAL: | |||||
if (ch == '$') { | |||||
state = 1; | |||||
} else { | |||||
ret.append(ch); | |||||
} | |||||
break; | |||||
case STATE_EXPECT_BRACKET: | |||||
if (ch == '{') { | |||||
state = 2; | |||||
macroName = new StringBuffer(); | |||||
} else { | |||||
state = 0; | |||||
ret.append('$'); | |||||
ret.append(ch); | |||||
} | |||||
break; | |||||
case STATE_EXPECT_NAME: | |||||
if (ch == '}') { | |||||
state = 0; | |||||
String name = macroName.toString(); | String name = macroName.toString(); | ||||
String value = (String) macroMapping.get(name); | String value = (String) macroMapping.get(name); | ||||
if (value == null) { | if (value == null) { | ||||
@@ -167,16 +205,23 @@ public class MacroInstance extends Task implements DynamicConfigurator { | |||||
} else { | } else { | ||||
ret.append(value); | ret.append(value); | ||||
} | } | ||||
macroName = new StringBuffer(); | |||||
inMacro = false; | |||||
macroName = null; | |||||
} else { | } else { | ||||
macroName.append(s.charAt(i)); | macroName.append(s.charAt(i)); | ||||
} | } | ||||
} else { | |||||
ret.append(s.charAt(i)); | |||||
} | |||||
} | } | ||||
} | } | ||||
switch (state) { | |||||
case STATE_NORMAL: | |||||
break; | |||||
case STATE_EXPECT_BRACKET: | |||||
ret.append('$'); | |||||
break; | |||||
case STATE_EXPECT_NAME: | |||||
ret.append("${"); | |||||
ret.append(macroName.toString()); | |||||
break; | |||||
} | |||||
return ret.toString(); | return ret.toString(); | ||||
} | } | ||||
@@ -212,15 +257,15 @@ public class MacroInstance extends Task implements DynamicConfigurator { | |||||
while (e.hasMoreElements()) { | while (e.hasMoreElements()) { | ||||
RuntimeConfigurable r = (RuntimeConfigurable) e.nextElement(); | RuntimeConfigurable r = (RuntimeConfigurable) e.nextElement(); | ||||
UnknownElement unknownElement = (UnknownElement) r.getProxy(); | UnknownElement unknownElement = (UnknownElement) r.getProxy(); | ||||
String tag = unknownElement.getTag(); | |||||
String tag = unknownElement.getTaskType(); | |||||
MacroDef.TemplateElement templateElement = | MacroDef.TemplateElement templateElement = | ||||
(MacroDef.TemplateElement) macroDef.getElements().get(tag); | |||||
(MacroDef.TemplateElement) getNsElements().get(tag); | |||||
if (templateElement == null) { | if (templateElement == null) { | ||||
UnknownElement child = copy(unknownElement); | UnknownElement child = copy(unknownElement); | ||||
rc.addChild(child.getWrapper()); | rc.addChild(child.getWrapper()); | ||||
ret.addChild(child); | ret.addChild(child); | ||||
} else { | } else { | ||||
Element element = (Element) elements.get(tag); | |||||
Element element = (Element) presentElements.get(tag); | |||||
if (element == null) { | if (element == null) { | ||||
if (!templateElement.isOptional()) { | if (!templateElement.isOptional()) { | ||||
throw new BuildException( | throw new BuildException( | ||||