From f2bc3fe7c89755a2e53e79aaf636b4177fe8928d Mon Sep 17 00:00:00 2001 From: Conor MacNeill Date: Wed, 1 Aug 2001 11:41:15 +0000 Subject: [PATCH] New Introspection capability. Methods which have the signature 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-ffa450edef68 --- .../apache/tools/ant/IntrospectionHelper.java | 76 ++++++++++++++++++- .../org/apache/tools/ant/ProjectHelper.java | 14 +++- .../apache/tools/ant/RuntimeConfigurable.java | 10 ++- src/main/org/apache/tools/ant/Task.java | 2 +- 4 files changed, 96 insertions(+), 6 deletions(-) diff --git a/src/main/org/apache/tools/ant/IntrospectionHelper.java b/src/main/org/apache/tools/ant/IntrospectionHelper.java index 6078ade10..bd437e794 100644 --- a/src/main/org/apache/tools/ant/IntrospectionHelper.java +++ b/src/main/org/apache/tools/ant/IntrospectionHelper.java @@ -90,6 +90,11 @@ public class IntrospectionHelper implements BuildListener { */ private Hashtable nestedCreators; + /** + * Holds methods to store configured nested elements. + */ + private Hashtable nestedStorers; + /** * The method to add PCDATA stuff. */ @@ -110,6 +115,8 @@ public class IntrospectionHelper implements BuildListener { attributeSetters = new Hashtable(); nestedTypes = new Hashtable(); nestedCreators = new Hashtable(); + nestedStorers = new Hashtable(); + this.bean = bean; 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") && java.lang.Void.TYPE.equals(returnType) && args.length == 1 @@ -202,7 +242,6 @@ public class IntrospectionHelper implements BuildListener { }); } 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. */ @@ -555,6 +623,12 @@ public class IntrospectionHelper implements BuildListener { public Object create(Object parent) throws InvocationTargetException, IllegalAccessException, InstantiationException; } + + private interface NestedStorer { + public void store(Object parent, Object child) + throws InvocationTargetException, IllegalAccessException, InstantiationException; + } + private interface AttributeSetter { public void set(Project p, Object parent, String value) throws InvocationTargetException, IllegalAccessException, diff --git a/src/main/org/apache/tools/ant/ProjectHelper.java b/src/main/org/apache/tools/ant/ProjectHelper.java index 50acab8db..ca321a74c 100644 --- a/src/main/org/apache/tools/ant/ProjectHelper.java +++ b/src/main/org/apache/tools/ant/ProjectHelper.java @@ -552,11 +552,12 @@ public class ProjectHelper { configureId(child, attrs); if (parentWrapper != null) { - childWrapper = new RuntimeConfigurable(child); + childWrapper = new RuntimeConfigurable(child, propType); childWrapper.setAttributes(attrs); parentWrapper.addChild(childWrapper); } else { configure(child, attrs, project); + ih.storeElement(project, parent, child, propType.toLowerCase()); } } catch (BuildException exc) { throw new SAXParseException(exc.getMessage(), locator, exc); @@ -612,7 +613,7 @@ public class ProjectHelper { } if (target != null) { - wrapper = new RuntimeConfigurable(element); + wrapper = new RuntimeConfigurable(element, propType); wrapper.setAttributes(attrs); target.addDataType(wrapper); } else { @@ -688,7 +689,14 @@ public class ProjectHelper { 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 * the corresponding data types. diff --git a/src/main/org/apache/tools/ant/RuntimeConfigurable.java b/src/main/org/apache/tools/ant/RuntimeConfigurable.java index cdd8420ee..893883ef7 100644 --- a/src/main/org/apache/tools/ant/RuntimeConfigurable.java +++ b/src/main/org/apache/tools/ant/RuntimeConfigurable.java @@ -68,6 +68,7 @@ import org.xml.sax.helpers.AttributeListImpl; */ public class RuntimeConfigurable { + private String elementTag = null; private Vector children = new Vector(); private Object wrappedObject = null; private AttributeList attributes; @@ -76,8 +77,9 @@ public class RuntimeConfigurable { /** * @param proxy The element to wrap. */ - public RuntimeConfigurable(Object proxy) { + public RuntimeConfigurable(Object proxy, String elementTag) { wrappedObject = proxy; + this.elementTag = elementTag; } void setProxy(Object proxy) { @@ -126,6 +128,11 @@ public class RuntimeConfigurable { addText(new String(buf, start, end)); } + public String getElementTag() { + return elementTag; + } + + /** * Configure the wrapped element and all children. */ @@ -145,6 +152,7 @@ public class RuntimeConfigurable { while (enum.hasMoreElements()) { RuntimeConfigurable child = (RuntimeConfigurable) enum.nextElement(); child.maybeConfigure(p); + ProjectHelper.storeChild(p, wrappedObject, child.wrappedObject, child.getElementTag().toLowerCase()); } if (id != null) { diff --git a/src/main/org/apache/tools/ant/Task.java b/src/main/org/apache/tools/ant/Task.java index 11d348865..4ef176a00 100644 --- a/src/main/org/apache/tools/ant/Task.java +++ b/src/main/org/apache/tools/ant/Task.java @@ -203,7 +203,7 @@ public abstract class Task { */ public RuntimeConfigurable getRuntimeConfigurableWrapper() { if (wrapper == null) { - wrapper = new RuntimeConfigurable(this); + wrapper = new RuntimeConfigurable(this, getTaskName()); } return wrapper; }