dlr 02/01/11 15:37:56
Modified: src/java/org/apache/stratum/xo Mapper.java
Log:
o Removed use of basePackage -- it made too many assumptions about how
the class hierarchy is structured. With it, child elements had to be
in the same package as their parent.
o Add CLASS_NAME constant to create hook for knowing what Class type a
XML entity is supposed to correspond to. Employeed hook in map() and
treeWalk().
o Consolidated debugging for addObject() and setProperties().
o Added elementClassName() method for use in discovering the class
name of a nested element (and allowing the removal the the "same
package" assumption).
o Improved interface to inclusion() method, removing unnecessary
paremeters.
o Renamed elementToClassName() to makeMethodName(). As its
assumptions about package structure didn't hold, it's now used only to
generate the name of the method used to add objects to a parent bean.
Revision Changes Path
1.6 +102 -70
jakarta-turbine-stratum/src/java/org/apache/stratum/xo/Mapper.java
Index: Mapper.java
===================================================================
RCS file:
/home/cvs/jakarta-turbine-stratum/src/java/org/apache/stratum/xo/Mapper.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -u -r1.5 -r1.6
--- Mapper.java 11 Jan 2002 04:10:18 -0000 1.5
+++ Mapper.java 11 Jan 2002 23:37:56 -0000 1.6
@@ -67,7 +67,7 @@
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.beanutils.ConvertUtils;
-import org.apache.commons.util.StringUtils;
+import org.apache.commons.util.FileUtils;
import java.lang.reflect.Method;
import org.apache.stratum.introspection.Introspector;
@@ -138,7 +138,7 @@
*
* @author <a href="mailto:[EMAIL PROTECTED]">Jason van Zyl</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Daniel Rall</a>
- * @version $Id: Mapper.java,v 1.5 2002/01/11 04:10:18 dlr Exp $
+ * @version $Id: Mapper.java,v 1.6 2002/01/11 23:37:56 dlr Exp $
*/
// How to use the resources package to pull in the
@@ -158,6 +158,19 @@
public class Mapper
{
+ /**
+ * The element and element attribute name which indicates the
+ * class name of the next object in the model.
+ */
+ protected static final String CLASS_NAME = "className";
+
+ /**
+ * The element attribute that indicates an external
+ * XML document is to be process and part of the construction
+ * of object model.
+ */
+ protected static final String EID = "id";
+
/**
* dom4j object model representation of a xml document. Note:
* We use the interface(!) not its implementation
@@ -165,12 +178,6 @@
private Document document;
/**
- * Base package of all the classes we may need to
- * create the specified object.
- */
- private String basePackage;
-
- /**
* Instructions for the inclusion of external files.
* If there is a rule that matches the element than files
* will be included from an external source.
@@ -189,13 +196,6 @@
private boolean debug = false;
/**
- * The element attribute that indicates and external
- * XML document is to be process and part of the construction
- * of object model.
- */
- private final static String EID = "id";
-
- /**
* Introspector that this mapper uses to determine
* properties and methods required to build up the
* object model.
@@ -227,7 +227,10 @@
*
* @param source The path (either classpath resource or file
* system) to the XML data file.
- * @param beanClass The fully qualified class name of the parent bean.
+ * @param beanClass The fully qualified class name of the parent
+ * bean, or <code>null</code> to read it from the
+ * <code>className</code> attribute of the first <code>Node</code>
+ * in the XML document.
* @return The fleshed-out instance of <code>beanClass</code>.
* @exception DocumentException If the buildprocess fails.
*/
@@ -245,16 +248,21 @@
SAXReader xmlReader = new SAXReader();
document = xmlReader.read(in);
- // Get the base package and directory
- int i = beanClass.lastIndexOf('.');
- basePackage = (i != -1 ? beanClass.substring(0, i) : "");
- basePath = StringUtils.replace(basePackage, ".", "/");
+ // Assure we have the beanClass
+ Element rootElement = document.getRootElement();
+ if (beanClass == null)
+ {
+ beanClass = elementClassName(rootElement);
+ }
+
+ // Get the base directory
+ basePath = FileUtils.dirname(source);
// Create the parent bean.
Object bean = Class.forName(beanClass).newInstance();
// Determine the base package to use for object creation.
- return treeWalk(document.getRootElement(), bean);
+ return treeWalk(rootElement, bean);
}
/**
@@ -268,15 +276,6 @@
}
/**
- * Get the base package of the parent object which
- * is at the top of the object model to build.
- */
- public String getBasePackage()
- {
- return basePackage;
- }
-
- /**
* Walk down a Element node processing the children.
*
* @param element Element to process
@@ -313,6 +312,7 @@
// (5): </address> ---+
if (hasChildren(node))
{
+ debug("Node " + node.getName() + " has children");
// We now have the situation where we need to
// instantiate a parent object so that elements
// that are subsequently processed can have their
@@ -323,13 +323,12 @@
// can be populated. We assume here that the
// object that we are creating is in the same
// package as the parent object.
- String className = basePackage + "." +
- elementToClassName(name);
-
+ String className = elementClassName((Element) node);
+
// We have to check for inclusion rules and build
// and object from an external XML file if that's
// the case.
- Object o = inclusion(node,name,bean);
+ Object o = inclusion((Element) node);
if (o == null)
{
@@ -337,16 +336,24 @@
try
{
// Should probably use the factory manager.
- o = Class.forName(className).newInstance();
+ Class c = Class.forName(className);
+ debug("c=" + c);
+ o = c.newInstance();
+ debug("o=" + o);
}
catch (Exception e)
{
- debug("Problem instantiating class: " + e);
+ debug("Problem instantiating class " +
+ className + ": " + e);
+ //e.printStackTrace(System.out);
}
- }
-
- debug("Created new object -> " + className);
-
+ }
+
+ if (o != null)
+ {
+ debug("Created new object -> " + className);
+ }
+
// Now we have to attach the newly created object
// to its parent object.
if (isPlural(node.getParent().getName()))
@@ -354,15 +361,13 @@
// Here we have the case where (A) is enclose by
// a parent element <addresses> so we need to add
// Address object to a List of Address objects.
- debug("add" + elementToClassName(name) + "(" + o + ")");
addObject(bean,name,o);
}
else
- {
+ {
// Here we have the case where (A) is NOT enclosed
// by a parent element <addresses> so we only need
// to set the simple property.
- debug("set" + elementToClassName(name) + "(" + o + ")");
setProperty(bean,name,o);
}
@@ -374,18 +379,19 @@
}
else
{
+ debug("Node " + node.getName() + " has no children");
// Now we are dealing with elements that refer
// to a noun singular and these elements have
// no children.
- Object o = inclusion(node,name,bean);
+ Object o = inclusion((Element) node);
Class type = null;
if (o == null)
{
type = PropertyUtils.getPropertyType(bean,name);
o = ConvertUtils.convert(node.getText(), type);
- }
+ }
if (isPlural(node.getParent().getName()))
{
@@ -400,7 +406,6 @@
// So the noun singular values of 'somnambulism'
// and 'squash' are added to a 'hobbies' list. We
// assume a List of Strings with the above pattern.
- debug("add" + elementToClassName(name) + "(" + o + ")");
addObject(bean, name, o);
}
else
@@ -416,7 +421,6 @@
// So with the noun singular values 'Jason' and
// 'van Zyl' we attempt to set simple bean
// properties.
- debug("set" + elementToClassName(name) + "(" + o + ")");
setProperty(bean,name,o);
}
}
@@ -444,6 +448,31 @@
// -------------------------------------------------------------------
/**
+ * Returns the fully qualified class name of <code>element</code>
+ * from its <code>className</code> attribute, or if that doesn't
+ * exist, then from its nested <code><pre><className></pre></code>
+ * element.
+ */
+ private String elementClassName(Element element)
+ throws Exception
+ {
+ String beanClass = element.attributeValue(CLASS_NAME);
+ if (beanClass == null)
+ {
+ // Try for a nested element of the same name.
+ beanClass = element.element(CLASS_NAME).getText();
+ if (beanClass == null)
+ {
+ throw new Exception
+ ("No class name for node '" + element.getName() +
+ "': This can be resolved by adding a " + CLASS_NAME +
+ " attribute or child node");
+ }
+ }
+ return beanClass;
+ }
+
+ /**
* Does the node in question have child nodes?
*
* @param node
@@ -457,38 +486,38 @@
* Build up and object by pulling in an external XML
* document.
*
- * @param node
- * @param name
- * @param bean
- * @return Object The Java object build up by the inclusion process
+ * @param node The <code>Element</code> currently being processed.
+ * @return The object build up by the inclusion process.
*/
- private Object inclusion(Node node,String name, Object bean)
+ private Object inclusion(Element node)
throws Exception
{
- String inclusionRule = (String) inclusionRules.get(name);
- Object x = null;
-
+ String inclusionRule = (String) inclusionRules.get(node.getName());
if (inclusionRule == null)
{
- return x;
+ return null;
}
-
- String className = basePackage + '.' + elementToClassName(name);
- String id = ((Element)node).attributeValue(EID);
StringBuffer path = new StringBuffer(basePath).append('/');
if (inclusionRule.length() > 0)
{
path.append(inclusionRule).append('/');
}
+ String id = node.attributeValue(EID);
+ if (id == null || id.length() == 0)
+ {
+ return null;
+ }
path.append(id).append(".xml");
- x = map(path.toString(), className);
+
+ // Passing null as the second arg will tell map() to look for
+ // a className attribute on the root element.
+ Object x = map(path.toString(), null);
if (x == null)
{
debug("ERROR: Problem loading -> " + node.getName() + ":" + x);
- }
-
+ }
return x;
}
@@ -496,16 +525,17 @@
* Add an object to a parent object
*
* @param bean
- * @param name
+ * @param elementName
* @param value
*/
private void addObject(Object bean, String elementName, Object value)
throws Exception
{
+ debug(makeMethodName("add", elementName) + '(' + value + ')');
try
{
Object[] args = new Object[] { value };
- String methodName = "add" + elementToClassName(elementName);
+ String methodName = makeMethodName("add", elementName);
Method m = introspector.getMethod(bean.getClass(), methodName, args);
if (m == null)
@@ -522,14 +552,15 @@
}
/**
- * Set a standard simple bean property
+ * Set a standard simple bean property.
*
* @param bean
- * @param name
+ * @param elementName
* @param value
*/
private void setProperty(Object bean, String elementName, Object value)
{
+ debug(makeMethodName("set", elementName) + '(' + value + ')');
try
{
PropertyUtils.setSimpleProperty(bean,elementName,value);
@@ -557,7 +588,7 @@
Object value)
{
String methodName = bean.getClass().getName() + "." +
- methodType + elementToClassName(elementName);
+ makeMethodName(methodType, elementName);
debug("ERROR: " + methodName + "(" + value.getClass().getName() + ") not
found!");
}
@@ -597,13 +628,14 @@
/**
* Makes the first letter capital and leaves the rest as is.
*
+ * @param prefix The method prefix (generally an action word).
* @param text The text to modify.
* @return The modified text.
*/
- private String elementToClassName(String text)
+ private String makeMethodName(String prefix, String text)
{
- return (text == null ? null :
- text.substring(0, 1).toUpperCase() + text.substring(1));
+ return (text == null ? null : prefix +
+ text.substring(0, 1).toUpperCase() + text.substring(1));
}
/**
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>