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]>

Reply via email to