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( | ||||