addConfiguredXXX will be called for nested elements named XXX but will be called only once the XXX object has been configured git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@269430 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -90,6 +90,11 @@ public class IntrospectionHelper implements BuildListener { | |||||
| */ | */ | ||||
| private Hashtable nestedCreators; | private Hashtable nestedCreators; | ||||
| /** | |||||
| * Holds methods to store configured nested elements. | |||||
| */ | |||||
| private Hashtable nestedStorers; | |||||
| /** | /** | ||||
| * The method to add PCDATA stuff. | * The method to add PCDATA stuff. | ||||
| */ | */ | ||||
| @@ -110,6 +115,8 @@ public class IntrospectionHelper implements BuildListener { | |||||
| attributeSetters = new Hashtable(); | attributeSetters = new Hashtable(); | ||||
| nestedTypes = new Hashtable(); | nestedTypes = new Hashtable(); | ||||
| nestedCreators = new Hashtable(); | nestedCreators = new Hashtable(); | ||||
| nestedStorers = new Hashtable(); | |||||
| this.bean = bean; | this.bean = bean; | ||||
| Method[] methods = bean.getMethods(); | Method[] methods = bean.getMethods(); | ||||
| @@ -177,6 +184,39 @@ public class IntrospectionHelper implements BuildListener { | |||||
| }); | }); | ||||
| } else if (name.startsWith("addConfigured") | |||||
| && java.lang.Void.TYPE.equals(returnType) | |||||
| && args.length == 1 | |||||
| && !java.lang.String.class.equals(args[0]) | |||||
| && !args[0].isArray() | |||||
| && !args[0].isPrimitive()) { | |||||
| try { | |||||
| final Constructor c = | |||||
| args[0].getConstructor(new Class[] {}); | |||||
| String propName = getPropertyName(name, "addConfigured"); | |||||
| nestedTypes.put(propName, args[0]); | |||||
| nestedCreators.put(propName, new NestedCreator() { | |||||
| public Object create(Object parent) | |||||
| throws InvocationTargetException, IllegalAccessException, InstantiationException { | |||||
| Object o = c.newInstance(new Object[] {}); | |||||
| return o; | |||||
| } | |||||
| }); | |||||
| nestedStorers.put(propName, new NestedStorer() { | |||||
| public void store(Object parent, Object child) | |||||
| throws InvocationTargetException, IllegalAccessException, InstantiationException { | |||||
| m.invoke(parent, new Object[] {child}); | |||||
| } | |||||
| }); | |||||
| } catch (NoSuchMethodException nse) { | |||||
| } | |||||
| } else if (name.startsWith("add") | } else if (name.startsWith("add") | ||||
| && java.lang.Void.TYPE.equals(returnType) | && java.lang.Void.TYPE.equals(returnType) | ||||
| && args.length == 1 | && args.length == 1 | ||||
| @@ -202,7 +242,6 @@ public class IntrospectionHelper implements BuildListener { | |||||
| }); | }); | ||||
| } catch (NoSuchMethodException nse) { | } catch (NoSuchMethodException nse) { | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -299,6 +338,35 @@ public class IntrospectionHelper implements BuildListener { | |||||
| } | } | ||||
| } | } | ||||
| /** | |||||
| * Creates a named nested element. | |||||
| */ | |||||
| public void storeElement(Project project, Object element, Object child, String elementName) | |||||
| throws BuildException { | |||||
| if (elementName == null) { | |||||
| return; | |||||
| } | |||||
| NestedStorer ns = (NestedStorer)nestedStorers.get(elementName); | |||||
| if (ns == null) { | |||||
| return; | |||||
| } | |||||
| try { | |||||
| ns.store(element, child); | |||||
| } catch (IllegalAccessException ie) { | |||||
| // impossible as getMethods should only return public methods | |||||
| throw new BuildException(ie); | |||||
| } catch (InstantiationException ine) { | |||||
| // impossible as getMethods should only return public methods | |||||
| throw new BuildException(ine); | |||||
| } catch (InvocationTargetException ite) { | |||||
| Throwable t = ite.getTargetException(); | |||||
| if (t instanceof BuildException) { | |||||
| throw (BuildException) t; | |||||
| } | |||||
| throw new BuildException(t); | |||||
| } | |||||
| } | |||||
| /** | /** | ||||
| * returns the type of a named nested element. | * returns the type of a named nested element. | ||||
| */ | */ | ||||
| @@ -555,6 +623,12 @@ public class IntrospectionHelper implements BuildListener { | |||||
| public Object create(Object parent) | public Object create(Object parent) | ||||
| throws InvocationTargetException, IllegalAccessException, InstantiationException; | throws InvocationTargetException, IllegalAccessException, InstantiationException; | ||||
| } | } | ||||
| private interface NestedStorer { | |||||
| public void store(Object parent, Object child) | |||||
| throws InvocationTargetException, IllegalAccessException, InstantiationException; | |||||
| } | |||||
| private interface AttributeSetter { | private interface AttributeSetter { | ||||
| public void set(Project p, Object parent, String value) | public void set(Project p, Object parent, String value) | ||||
| throws InvocationTargetException, IllegalAccessException, | throws InvocationTargetException, IllegalAccessException, | ||||
| @@ -552,11 +552,12 @@ public class ProjectHelper { | |||||
| configureId(child, attrs); | configureId(child, attrs); | ||||
| if (parentWrapper != null) { | if (parentWrapper != null) { | ||||
| childWrapper = new RuntimeConfigurable(child); | |||||
| childWrapper = new RuntimeConfigurable(child, propType); | |||||
| childWrapper.setAttributes(attrs); | childWrapper.setAttributes(attrs); | ||||
| parentWrapper.addChild(childWrapper); | parentWrapper.addChild(childWrapper); | ||||
| } else { | } else { | ||||
| configure(child, attrs, project); | configure(child, attrs, project); | ||||
| ih.storeElement(project, parent, child, propType.toLowerCase()); | |||||
| } | } | ||||
| } catch (BuildException exc) { | } catch (BuildException exc) { | ||||
| throw new SAXParseException(exc.getMessage(), locator, exc); | throw new SAXParseException(exc.getMessage(), locator, exc); | ||||
| @@ -612,7 +613,7 @@ public class ProjectHelper { | |||||
| } | } | ||||
| if (target != null) { | if (target != null) { | ||||
| wrapper = new RuntimeConfigurable(element); | |||||
| wrapper = new RuntimeConfigurable(element, propType); | |||||
| wrapper.setAttributes(attrs); | wrapper.setAttributes(attrs); | ||||
| target.addDataType(wrapper); | target.addDataType(wrapper); | ||||
| } else { | } else { | ||||
| @@ -688,7 +689,14 @@ public class ProjectHelper { | |||||
| IntrospectionHelper.getHelper(target.getClass()).addText(project, target, text); | IntrospectionHelper.getHelper(target.getClass()).addText(project, target, text); | ||||
| } | } | ||||
| /** | |||||
| * Stores a configured child element into its parent object | |||||
| */ | |||||
| public static void storeChild(Project project, Object parent, Object child, String tag) { | |||||
| IntrospectionHelper ih = IntrospectionHelper.getHelper(parent.getClass()); | |||||
| ih.storeElement(project, parent, child, tag); | |||||
| } | |||||
| /** | /** | ||||
| * Replace ${} style constructions in the given value with the string value of | * Replace ${} style constructions in the given value with the string value of | ||||
| * the corresponding data types. | * the corresponding data types. | ||||
| @@ -68,6 +68,7 @@ import org.xml.sax.helpers.AttributeListImpl; | |||||
| */ | */ | ||||
| public class RuntimeConfigurable { | public class RuntimeConfigurable { | ||||
| private String elementTag = null; | |||||
| private Vector children = new Vector(); | private Vector children = new Vector(); | ||||
| private Object wrappedObject = null; | private Object wrappedObject = null; | ||||
| private AttributeList attributes; | private AttributeList attributes; | ||||
| @@ -76,8 +77,9 @@ public class RuntimeConfigurable { | |||||
| /** | /** | ||||
| * @param proxy The element to wrap. | * @param proxy The element to wrap. | ||||
| */ | */ | ||||
| public RuntimeConfigurable(Object proxy) { | |||||
| public RuntimeConfigurable(Object proxy, String elementTag) { | |||||
| wrappedObject = proxy; | wrappedObject = proxy; | ||||
| this.elementTag = elementTag; | |||||
| } | } | ||||
| void setProxy(Object proxy) { | void setProxy(Object proxy) { | ||||
| @@ -126,6 +128,11 @@ public class RuntimeConfigurable { | |||||
| addText(new String(buf, start, end)); | addText(new String(buf, start, end)); | ||||
| } | } | ||||
| public String getElementTag() { | |||||
| return elementTag; | |||||
| } | |||||
| /** | /** | ||||
| * Configure the wrapped element and all children. | * Configure the wrapped element and all children. | ||||
| */ | */ | ||||
| @@ -145,6 +152,7 @@ public class RuntimeConfigurable { | |||||
| while (enum.hasMoreElements()) { | while (enum.hasMoreElements()) { | ||||
| RuntimeConfigurable child = (RuntimeConfigurable) enum.nextElement(); | RuntimeConfigurable child = (RuntimeConfigurable) enum.nextElement(); | ||||
| child.maybeConfigure(p); | child.maybeConfigure(p); | ||||
| ProjectHelper.storeChild(p, wrappedObject, child.wrappedObject, child.getElementTag().toLowerCase()); | |||||
| } | } | ||||
| if (id != null) { | if (id != null) { | ||||
| @@ -203,7 +203,7 @@ public abstract class Task { | |||||
| */ | */ | ||||
| public RuntimeConfigurable getRuntimeConfigurableWrapper() { | public RuntimeConfigurable getRuntimeConfigurableWrapper() { | ||||
| if (wrapper == null) { | if (wrapper == null) { | ||||
| wrapper = new RuntimeConfigurable(this); | |||||
| wrapper = new RuntimeConfigurable(this, getTaskName()); | |||||
| } | } | ||||
| return wrapper; | return wrapper; | ||||
| } | } | ||||