package com.javaranch.dynadto; import java.lang.reflect.Constructor; import java.util.ArrayList; import org.apache.commons.beanutils.BasicDynaClass; import org.apache.commons.beanutils.DynaClass; import org.apache.commons.beanutils.DynaProperty; import org.apache.commons.digester.*; import org.xml.sax.Attributes; /** * A RuleSet for parsing the dto-config.xml file to create Dynamic * Data Transfer Objects. * @author Jason Menard * @version 1.0 */ public class DynaDTORuleSet extends RuleSetBase { public void addRuleInstances(Digester digester) { digester.addFactoryCreate("dto-config/dto", new DynaClassFactory()); digester.addRule("dto-config/dto/property", new AddPropertyRule()); digester.addRule("dto-config/dto", new AddPropertiesRule()); } } final class AddPropertiesRule extends Rule { public void end(String namespace, String name) { ArrayList list = new ArrayList(); while (digester.peek() instanceof DynaProperty) { list.add(digester.pop()); } int size = list.size(); DynaProperty[] properties = new DynaProperty[size]; // Maintain property order specified in dto-config.xml. // The last element of list is the first property that was // added to the stack. for (int i = 0; i < size; i++) { properties[i] = (DynaProperty) list.get(size - i - 1); } // all the properties have been popped off leaving a DynaClass // on top of the stack DynaDTODynaClass dynaClass = (DynaDTODynaClass) digester.peek(); dynaClass.setProperties(properties); // The DynaDTOFactory is one level beneath the DynaClass on the stack DynaDTOFactory factory = (DynaDTOFactory) digester.peek(1); factory.addDynaClass(dynaClass); } } final class AddPropertyRule extends Rule { public void begin(String namespace, String name, Attributes attributes) throws Exception { String propertyName = attributes.getValue("name"); Class type = Class.forName(attributes.getValue("type")); digester.push(new DynaProperty(propertyName, type)); } } final class DynaClassFactory extends AbstractObjectCreationFactory { private final String DEFAULT_DYNA_BEAN = "com.javaranch.dynadto.DynaDTODynaBean"; private final String DYNA_BEAN = "org.apache.commons.beanutils.DynaBean"; public Object createObject(Attributes attributes) throws Exception { String className = attributes.getValue("type"); String name = attributes.getValue("name"); if (className == null) { className = DEFAULT_DYNA_BEAN; } Class c = Class.forName(className); if(!(Class.forName(DYNA_BEAN)).isAssignableFrom(c)) { throw new Exception(className + " does not implement " + DYNA_BEAN); } Class[] constructorClassArgs = {java.lang.String.class, java.lang.Class.class}; Constructor constructor = DynaDTODynaClass.class.getConstructor(constructorClassArgs); Object[] constructorArgs = {name, c}; Object dynaClass = constructor.newInstance(constructorArgs); return dynaClass; } }