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> | |||
| <current:if> | |||
| <current:isallowed test="${action}"/> | |||
| <then> | |||
| <do/> | |||
| </then> | |||
| <current:then> | |||
| <current:do/> | |||
| </current:then> | |||
| </current:if> | |||
| </sequential> | |||
| </macrodef> | |||
| @@ -642,6 +642,52 @@ public final class IntrospectionHelper implements BuildListener { | |||
| 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 | |||
| * 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. | |||
| * | |||
| * @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 | |||
| * create and store and instance of a subelement. | |||
| * @param elementName Name of the element to create an instance of. | |||
| @@ -699,8 +746,9 @@ public final class IntrospectionHelper implements BuildListener { | |||
| */ | |||
| 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); | |||
| } | |||
| @@ -718,6 +766,26 @@ public final class IntrospectionHelper implements BuildListener { | |||
| || 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 | |||
| * by the initial introspection. If no appropriate storage method | |||
| @@ -525,12 +525,29 @@ public class ProjectHelper { | |||
| * @return The uri or "" if not present | |||
| */ | |||
| public static String extractUriFromComponentName(String componentName) { | |||
| if (componentName == null) { | |||
| return ""; | |||
| } | |||
| int index = componentName.lastIndexOf(':'); | |||
| if (index == -1) { | |||
| return ""; | |||
| } | |||
| 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. | |||
| @@ -493,7 +493,7 @@ public abstract class Task extends ProjectComponent { | |||
| * | |||
| * @return the type of task | |||
| */ | |||
| protected String getTaskType() { | |||
| public String getTaskType() { | |||
| return taskType; | |||
| } | |||
| @@ -336,13 +336,15 @@ public class UnknownElement extends Task { | |||
| * | |||
| * @exception BuildException if the children cannot be configured. | |||
| */ | |||
| protected void handleChildren(Object parent, | |||
| RuntimeConfigurable parentWrapper) | |||
| protected void handleChildren( | |||
| Object parent, | |||
| RuntimeConfigurable parentWrapper) | |||
| throws BuildException { | |||
| if (parent instanceof TypeAdapter) { | |||
| parent = ((TypeAdapter) parent).getProxy(); | |||
| } | |||
| String parentUri = getNamespace(); | |||
| Class parentClass = parent.getClass(); | |||
| IntrospectionHelper ih = IntrospectionHelper.getHelper(parentClass); | |||
| @@ -352,8 +354,8 @@ public class UnknownElement extends Task { | |||
| for (int i = 0; it.hasNext(); i++) { | |||
| RuntimeConfigurable childWrapper = parentWrapper.getChild(i); | |||
| UnknownElement child = (UnknownElement) it.next(); | |||
| if (!handleChild(ih, parent, child, | |||
| childWrapper)) { | |||
| if (!handleChild( | |||
| parentUri, ih, parent, child, childWrapper)) { | |||
| if (!(parent instanceof TaskContainer)) { | |||
| ih.throwNotSupported(getProject(), parent, | |||
| child.getTag()); | |||
| @@ -548,14 +550,16 @@ public class UnknownElement extends Task { | |||
| * | |||
| * @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( | |||
| child.getNamespace(), child.getTag()); | |||
| if (ih.supportsNestedElement(childName)) { | |||
| if (ih.supportsNestedElement(parentUri, childName)) { | |||
| IntrospectionHelper.Creator creator = | |||
| ih.getElementCreator(getProject(), parent, childName); | |||
| ih.getElementCreator(getProject(), parentUri, parent, childName); | |||
| creator.setPolyType(childWrapper.getPolyType()); | |||
| Object realChild = creator.create(); | |||
| if (realChild instanceof PreSetDef.PreSetDefinition) { | |||
| @@ -939,8 +939,9 @@ public class ProjectHelper2 extends ProjectHelper { | |||
| UnknownElement task = new UnknownElement(tag); | |||
| task.setProject(context.getProject()); | |||
| task.setNamespace(uri); | |||
| //XXX task.setTaskType(qname); | |||
| task.setQName(qname); | |||
| task.setTaskType( | |||
| ProjectHelper.genComponentName(task.getNamespace(), tag)); | |||
| task.setTaskName(qname); | |||
| Location location = new Location(context.getLocator().getSystemId(), | |||
| @@ -84,8 +84,10 @@ import org.apache.tools.ant.UnknownElement; | |||
| public class MacroInstance extends Task implements DynamicConfigurator { | |||
| private MacroDef macroDef; | |||
| private Map map = new HashMap(); | |||
| private Map elements = new HashMap(); | |||
| private Map nsElements = null; | |||
| private Map presentElements = new HashMap(); | |||
| private Hashtable localProperties = new Hashtable(); | |||
| /** | |||
| * Called from MacroDef.MyAntTypeDefinition#create() | |||
| @@ -114,17 +116,33 @@ public class MacroInstance extends Task implements DynamicConfigurator { | |||
| * has already been seen | |||
| */ | |||
| public Object createDynamicElement(String name) throws BuildException { | |||
| if (macroDef.getElements().get(name) == null) { | |||
| if (getNsElements().get(name) == null) { | |||
| throw new BuildException("unsupported element " + name); | |||
| } | |||
| if (elements.get(name) != null) { | |||
| if (presentElements.get(name) != null) { | |||
| throw new BuildException("Element " + name + " already present"); | |||
| } | |||
| Element ret = new Element(); | |||
| elements.put(name, ret); | |||
| presentElements.put(name, 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 | |||
| */ | |||
| @@ -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) { | |||
| StringBuffer ret = new StringBuffer(); | |||
| StringBuffer macroName = new StringBuffer(); | |||
| StringBuffer macroName = null; | |||
| boolean inMacro = false; | |||
| int state = STATE_NORMAL; | |||
| 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 value = (String) macroMapping.get(name); | |||
| if (value == null) { | |||
| @@ -167,16 +205,23 @@ public class MacroInstance extends Task implements DynamicConfigurator { | |||
| } else { | |||
| ret.append(value); | |||
| } | |||
| macroName = new StringBuffer(); | |||
| inMacro = false; | |||
| macroName = null; | |||
| } else { | |||
| 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(); | |||
| } | |||
| @@ -212,15 +257,15 @@ public class MacroInstance extends Task implements DynamicConfigurator { | |||
| while (e.hasMoreElements()) { | |||
| RuntimeConfigurable r = (RuntimeConfigurable) e.nextElement(); | |||
| UnknownElement unknownElement = (UnknownElement) r.getProxy(); | |||
| String tag = unknownElement.getTag(); | |||
| String tag = unknownElement.getTaskType(); | |||
| MacroDef.TemplateElement templateElement = | |||
| (MacroDef.TemplateElement) macroDef.getElements().get(tag); | |||
| (MacroDef.TemplateElement) getNsElements().get(tag); | |||
| if (templateElement == null) { | |||
| UnknownElement child = copy(unknownElement); | |||
| rc.addChild(child.getWrapper()); | |||
| ret.addChild(child); | |||
| } else { | |||
| Element element = (Element) elements.get(tag); | |||
| Element element = (Element) presentElements.get(tag); | |||
| if (element == null) { | |||
| if (!templateElement.isOptional()) { | |||
| throw new BuildException( | |||