commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rdon...@apache.org
Subject cvs commit: jakarta-commons/betwixt/xdocs overview.xml tasks.xml
Date Sun, 09 Feb 2003 22:27:18 GMT
rdonkin     2003/02/09 14:27:18

  Modified:    betwixt/src/java/org/apache/commons/betwixt/io
                        BeanCreateRule.java BeanReader.java
               betwixt/src/test/org/apache/commons/betwixt
                        TestBeanReader.java
               betwixt/src/test/org/apache/commons/betwixt/digester
                        TestIDRead.java
               betwixt/src/test/org/apache/commons/betwixt/schema Dbms.java
                        PhysicalSchema.java TestSchema.java
               betwixt/xdocs overview.xml tasks.xml
  Added:       betwixt/src/java/org/apache/commons/betwixt/io
                        BeanRuleSet.java
               betwixt/src/test/org/apache/commons/betwixt ListOfNames.java
                        NameBean.java
  Log:
  Deprecated BeanCreateRule and replaced this wih BeanRuleSet. This Ruleset has been designed to allow easy integration with other Rules. Also added test cases. Now users can reliably add extra Digester Rules to BeanReader which safely interact with the standard betwixt mapping rules.
  
  Revision  Changes    Path
  1.20      +2 -0      jakarta-commons/betwixt/src/java/org/apache/commons/betwixt/io/BeanCreateRule.java
  
  Index: BeanCreateRule.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/betwixt/src/java/org/apache/commons/betwixt/io/BeanCreateRule.java,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -r1.19 -r1.20
  --- BeanCreateRule.java	6 Feb 2003 19:38:16 -0000	1.19
  +++ BeanCreateRule.java	9 Feb 2003 22:27:17 -0000	1.20
  @@ -85,6 +85,8 @@
     * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
     * @author <a href="mailto:martin@mvdb.net">Martin van den Bemt</a>
     * @version $Revision$
  +  * @deprecated this Rule does not allowed good integration with other Rules -
  +  * use {@link BeanRuleSet} instead.
     */
   public class BeanCreateRule extends Rule {
   
  
  
  
  1.11      +78 -11    jakarta-commons/betwixt/src/java/org/apache/commons/betwixt/io/BeanReader.java
  
  Index: BeanReader.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/betwixt/src/java/org/apache/commons/betwixt/io/BeanReader.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- BeanReader.java	8 Jan 2003 22:07:21 -0000	1.10
  +++ BeanReader.java	9 Feb 2003 22:27:17 -0000	1.11
  @@ -72,12 +72,16 @@
   import org.apache.commons.betwixt.XMLIntrospector;
   import org.apache.commons.digester.Digester;
   import org.apache.commons.digester.Rule;
  +import org.apache.commons.digester.RuleSet;
   import org.apache.commons.logging.Log;
   import org.apache.commons.logging.LogFactory;
   import org.xml.sax.XMLReader;
   
   /** <p><code>BeanReader</code> reads a tree of beans from an XML document.</p>
     *
  +  * <p>Call {@link #registerBeanClass(Class)} or {@link #registerBeanClass(String, Class)}
  +  * to add rules to map a bean class.</p>
  +  *
     * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
     * @version $Revision$
     */
  @@ -126,8 +130,23 @@
   
       
       /** 
  -     * Registers a bean class which is used by the reader
  -     * to deduce the digester rules.
  +     * <p>Register a bean class and add mapping rules for this bean class.</p>
  +     * 
  +     * <p>A bean class is introspected when it is registered.
  +     * It will <strong>not</strong> be introspected again even if the introspection
  +     * settings are changed.
  +     * If re-introspection is required, then {@link #deregisterBeanClass} must be called 
  +     * and the bean re-registered.</p>
  +     *
  +     * <p>A bean class can only be registered once. 
  +     * If the same class is registered a second time, this registration will be ignored.
  +     * In order to change a registration, call {@link #deregisterBeanClass} 
  +     * before calling this method.</p>
  +     *
  +     * <p>All the rules required to digest this bean are added when this method is called.
  +     * Other rules that you want to execute before these should be added before this
  +     * method is called. 
  +     * Those that should be executed afterwards, should be added afterwards.</p>
        *
        * @param beanClass the <code>Class</code> to be registered
        * @throws IntrospectionException if the bean introspection fails
  @@ -149,12 +168,34 @@
               }
               addBeanCreateRule( path, elementDescriptor, beanClass );
               addBeanCreateRule( "*/" + path, elementDescriptor, beanClass );
  +            
  +        } else {
  +            if ( log.isWarnEnabled() ) {
  +                log.warn("Cannot add class "  + beanClass.getName() + " since it already exists");
  +            }
           }
       }
       
       /** 
  -     * Registers a bean class at the given path expression 
  -     * which is used by the reader to deduce the digester rules.
  +     * <p>Registers a bean class  
  +     * and add mapping rules for this bean class at the given path expression.</p>
  +     * 
  +     * 
  +     * <p>A bean class is introspected when it is registered.
  +     * It will <strong>not</strong> be introspected again even if the introspection
  +     * settings are changed.
  +     * If re-introspection is required, then {@link #deregisterBeanClass} must be called 
  +     * and the bean re-registered.</p>
  +     *
  +     * <p>A bean class can only be registered once. 
  +     * If the same class is registered a second time, this registration will be ignored.
  +     * In order to change a registration, call {@link #deregisterBeanClass} 
  +     * before calling this method.</p>
  +     *
  +     * <p>All the rules required to digest this bean are added when this method is called.
  +     * Other rules that you want to execute before these should be added before this
  +     * method is called. 
  +     * Those that should be executed afterwards, should be added afterwards.</p>
        *
        * @param path the xml path expression where the class is to registered. 
        * This should be in digester path notation
  @@ -171,10 +212,40 @@
   
               addBeanCreateRule( path, elementDescriptor, beanClass );
           } else {
  -            log.warn("Cannot add class "  + beanClass.getName() + " since it already exists");
  +            if ( log.isWarnEnabled() ) {
  +                log.warn("Cannot add class "  + beanClass.getName() + " since it already exists");
  +            }
           }
       }
       
  +    /**
  +     * <p>Flush all registered bean classes.
  +     * This allows all bean classes to be re-registered 
  +     * by a subsequent calls to <code>registerBeanClass</code>.</p>
  +     *
  +     * <p><strong>Note</strong> that deregistering a bean does <strong>not</strong>
  +     * remove the Digester rules associated with that bean.</p>
  +     */
  +    public void flushRegisteredBeanClasses() {    
  +        registeredClasses.clear();
  +    }
  +    
  +    /**
  +     * <p>Remove the given class from the register.
  +     * Calling this method will allow the bean class to be re-registered 
  +     * by a subsequent call to <code>registerBeanClass</code>.
  +     * This allows (for example) a bean to be reintrospected after a change
  +     * to the introspection settings.</p>
  +     *
  +     * <p><strong>Note</strong> that deregistering a bean does <strong>not</strong>
  +     * remove the Digester rules associated with that bean.</p>
  +     *
  +     * @param beanClass the <code>Class</code> to remove from the set of registered bean classes
  +     */
  +    public void deregisterBeanClass( Class beanClass ) {
  +        registeredClasses.remove( beanClass );
  +    }
  +    
       // Properties
       //-------------------------------------------------------------------------        
   
  @@ -259,12 +330,8 @@
                                       String path, 
                                       ElementDescriptor elementDescriptor, 
                                       Class beanClass ) {
  -        Rule rule = new BeanCreateRule( elementDescriptor, beanClass, path + "/" , matchIDs);
  -        addRule( path, rule );
  -
  -        if ( log.isDebugEnabled() ) {
  -            log.debug( "Added root rule to path: " + path + " rule: " + rule );
  -        }
  +        RuleSet ruleSet = new BeanRuleSet( introspector, path ,  elementDescriptor, beanClass, matchIDs);
  +        addRuleSet( ruleSet );
       }
           
   }
  
  
  
  1.1                  jakarta-commons/betwixt/src/java/org/apache/commons/betwixt/io/BeanRuleSet.java
  
  Index: BeanRuleSet.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/betwixt/src/java/org/apache/commons/betwixt/io/BeanRuleSet.java,v 1.1 2003/02/09 22:27:17 rdonkin Exp $
   * $Revision: 1.1 $
   * $Date: 2003/02/09 22:27:17 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2003 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Commons", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   * 
   * $Id: BeanRuleSet.java,v 1.1 2003/02/09 22:27:17 rdonkin Exp $
   */
  package org.apache.commons.betwixt.io;
  
  import java.util.HashMap;
  import java.util.Map;
  import java.util.Iterator;
  
  import org.apache.commons.betwixt.AttributeDescriptor;
  import org.apache.commons.betwixt.ElementDescriptor;
  import org.apache.commons.betwixt.XMLBeanInfo;
  import org.apache.commons.betwixt.XMLIntrospector;
  import org.apache.commons.betwixt.digester.XMLIntrospectorHelper;
  import org.apache.commons.betwixt.expression.Context;
  import org.apache.commons.betwixt.expression.MethodUpdater;
  import org.apache.commons.betwixt.expression.Updater;
  import org.apache.commons.digester.Rule;
  import org.apache.commons.digester.Digester;
  import org.apache.commons.digester.RuleSet;
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  import org.xml.sax.Attributes;
  
  /** <p>Sets <code>Betwixt</code> digestion rules for a bean class.</p>
    *
    * @author <a href="mailto:rdonkin@apache.org">Robert Burrell Donkin</a>
    * @version $Revision: 1.1 $
    */
  public class BeanRuleSet implements RuleSet {
      
      
      /** Logger */
      private static Log log = LogFactory.getLog( BeanRuleSet.class );
      
      /** 
      * Set log to be used by <code>BeanRuleSet</code> instances 
      * @param aLog the <code>Log</code> implementation for this class to log to
      */
      public static void setLog(Log aLog) {
          log = aLog;
      }
      
      /** Use this to introspect beans */
      private XMLIntrospector introspector;
      /** The base path under which the rules will be attached */
      private String basePath;
      /** The element descriptor for the base  */
      private ElementDescriptor baseElementDescriptor;
      /** The bean based  */
      private Class baseBeanClass;
      /** Should ID/IDREFs be used to match beans created previously  */
      private boolean matchIDs;
      
      /**
       * Base constructor.
       *
       * @param introspector the <code>XMLIntrospector</code> used to introspect 
       * @param basePath specifies the (Digester-style) path under which the rules will be attached
       * @param baseElementDescriptor the <code>ElementDescriptor</code> used to create the rules
       * @param baseBeanClass the <code>Class</code> whose mapping rules will be created
       * @param matchIDs should ID/IDREFs be used to match beans?
       */
      public BeanRuleSet(
                          XMLIntrospector introspector,
                          String basePath, 
                          ElementDescriptor baseElementDescriptor, 
                          Class baseBeanClass,
                          boolean matchIDs) {
          this.introspector = introspector;
          this.basePath = basePath;
          this.baseElementDescriptor = baseElementDescriptor;
          this.baseBeanClass = baseBeanClass;
          this.matchIDs = matchIDs;
      }
      
  //-------------------------------- Ruleset implementation
  
      /** 
       * <p>Return namespace associated with this ruleset</p>
       *
       * <p><strong>Note</strong> namespaces are not currently supported.</p>
       * 
       * @return null
       */
      public String getNamespaceURI() {
          return null;
      }
      
      /**
       * Add rules for bean to given <code>Digester</code>.
       *
       * @param digester the <code>Digester</code> to which the rules for the bean will be added
       */
      public void addRuleInstances(Digester digester) {
          ReadContext readContext = new ReadContext( digester );
      }
      
      /**
       * <p>A set of associated rules that maps a bean graph.
       * An instance will be created each time {@link #addRuleInstances} is called.</p>
       *
       * <p>When an instance is constructed, rules are created and added to digester.</p>
       */
      private class ReadContext {
          /** The beans created by rules in this context indexed by id */
          private Map beansById =  new HashMap();
          /** The rules in this context indexed by path */
          private Map rulesByPath = new HashMap();
          
          /** 
           * Creates rules for bean and adds them to digester 
           * @param digester the <code>Digester</code> 
           * to which the bean mapping rules will be added
           */
          ReadContext(Digester digester) {
          
              BeanRule rule = new BeanRule( basePath + "/" , baseElementDescriptor, baseBeanClass );
              addRule( basePath, rule , baseElementDescriptor, rule.context );
              
              if ( log.isDebugEnabled() ) {
                  log.debug( "Added root rule to path: " + basePath + " class: " + baseBeanClass );
              } 
              
              
              Iterator it = rulesByPath.entrySet().iterator();
              while (it.hasNext()) {
                  Map.Entry entry = (Map.Entry) it.next();
                  if ( log.isTraceEnabled() ) {
                      log.trace("Added rule:" + entry.getValue() + " @path:" + entry.getKey());
                  }
                  digester.addRule( (String) entry.getKey() , (Rule) entry.getValue() );
              }
          }
                                                                      
          /** 
          * Add child rules for given descriptor at given prefix 
          *
          * @param prefix add child rules at this (digester) path prefix
          * @param currentDescriptor add child rules for this descriptor
          * @param context the <code>Context</code> against which beans will be evaluated 
          */
          private void addChildRules( 	
                                      String prefix, 
                                      ElementDescriptor currentDescriptor, 
                                      Context context ) {
              
              if (log.isTraceEnabled()) {
                  log.trace("Adding child rules for " + currentDescriptor + "@" + prefix);
              }
              
              // if we are a reference to a type we should lookup the original
              // as this ElementDescriptor will be 'hollow' and have no child attributes/elements.
              // XXX: this should probably be done by the NodeDescriptors...
              ElementDescriptor typeDescriptor = getElementDescriptor( currentDescriptor );
              //ElementDescriptor typeDescriptor = descriptor;
      
              
              ElementDescriptor[] childDescriptors = typeDescriptor.getElementDescriptors();
              if ( childDescriptors != null ) {
                  for ( int i = 0, size = childDescriptors.length; i < size; i++ ) {
                      final ElementDescriptor childDescriptor = childDescriptors[i];
                      if (log.isTraceEnabled()) {
                          log.trace("Processing child " + childDescriptor);
                      }
                      
                      String propertyName = childDescriptor.getPropertyName();
                      String qualifiedName = childDescriptor.getQualifiedName();
                      if ( qualifiedName == null ) {
                          log.trace( "Ignoring" );
                          continue;
                      }
                      String path = prefix + qualifiedName;
                      // this code is for making sure that recursive elements
                      // can also be used..
                      
                      if ( qualifiedName.equals( currentDescriptor.getQualifiedName() ) 
                              && currentDescriptor.getPropertyName() != null ) {
                          log.trace("Creating generic rule for recursive elements");
                          int index = -1;
                          if (childDescriptor.isWrapCollectionsInElement()) {
                              index = prefix.indexOf(qualifiedName);
                              if (index == -1) {
                                  // shouldn't happen.. 
                                  log.debug( "Oops - this shouldn't happen" );
                                  continue;
                              }
                              int removeSlash = prefix.endsWith("/")?1:0;
                              path = "*/" + prefix.substring(index, prefix.length()-removeSlash);
                          }else{
                              // we have a element/element type of thing..
                              ElementDescriptor[] desc = currentDescriptor.getElementDescriptors();
                              if (desc.length == 1) {
                                  path = "*/"+desc[0].getQualifiedName();
                              }
                          }
                          addRule( path, childDescriptor, context );
                          continue;
                      }
                      if ( childDescriptor.getUpdater() != null ) {
                          if (log.isTraceEnabled()) {
                              log.trace("Element has updater "
                              + ((MethodUpdater) childDescriptor.getUpdater()).getMethod().getName());
                          }
                          if ( childDescriptor.isPrimitiveType() ) {
                              addPrimitiveTypeRule( path, childDescriptor, context );
                              
                          } else {
                              // add the first child to the path
                              ElementDescriptor[] grandChildren 
                                  = childDescriptor.getElementDescriptors();
                              if ( grandChildren != null && grandChildren.length > 0 ) {
                                  ElementDescriptor grandChild = grandChildren[0];
                                  String grandChildQName = grandChild.getQualifiedName();
                                  if ( grandChildQName != null && grandChildQName.length() > 0 ) {
                                      if (childDescriptor.isWrapCollectionsInElement()) {
                                          path += '/' + grandChildQName;
                                          
                                      } else {
                                          path = prefix 
                                              + (prefix.endsWith("/")?"":"/") + grandChildQName;
                                      }
                                  }
                              }
                              
                              // maybe we are adding a primitve type to a collection/array
                              Class beanClass = childDescriptor.getSingularPropertyType();
                              if ( XMLIntrospectorHelper.isPrimitiveType( beanClass ) ) {
                                  addPrimitiveTypeRule( path, childDescriptor, context );
                                  
                              } else {
                                  addRule( path, childDescriptor,  context );
                              }
                          }
                      } else {
                          log.trace("Element does not have updater");
                      }
      
                      ElementDescriptor[] grandChildren = childDescriptor.getElementDescriptors();
                      if ( grandChildren != null && grandChildren.length > 0 ) {
                          if ( log.isTraceEnabled() ) {
                              log.trace("Adding grand children @path:" + path);
                          }
                          addChildRules( path + '/', childDescriptor, context );
                      }
                  }
              }
          }
          
          /** Allows the navigation from a reference to a property object to the 
          * descriptor defining what the property is. i.e. doing the join from a reference 
          * to a type to lookup its descriptor.
          * This could be done automatically by the NodeDescriptors. 
          * Refer to TODO.txt for more info.
          *
          * @param propertyDescriptor find descriptor for property object 
          * referenced by this descriptor
          * @return descriptor for the singular property class type referenced.
          */
          ElementDescriptor getElementDescriptor( ElementDescriptor propertyDescriptor ) {
              Class beanClass = propertyDescriptor.getSingularPropertyType();
              if ( beanClass != null ) {
                  try {
                      XMLBeanInfo xmlInfo = introspector.introspect( beanClass );
                      return xmlInfo.getElementDescriptor();
                      
                  } catch (Exception e) {
                      log.warn( "Could not introspect class: " + beanClass, e );
                  }
              }
              // could not find a better descriptor so use the one we've got
              return propertyDescriptor;
          }
          
          /** 
          * Adds a new Digester rule to process the text as a primitive type
          *
          * @param path digester path where this rule will be attached
          * @param childDescriptor update this <code>ElementDescriptor</code> with the body text
          * @param context the <code>Context</code> against which the elements will be evaluated 
          */
          void addPrimitiveTypeRule(
                                  String path, 
                                  final ElementDescriptor childDescriptor, 
                                  final Context context) {
                                  
              Rule rule = new Rule() {
                  public void body(String text) throws Exception {
                      childDescriptor.getUpdater().update( context, text );
                  }        
              };
              add( path, rule );
          }
          
          /** 
          * Adds a new Digester rule to process the text as a primitive type
          *
          * @param path digester path where this rule will be attached
          * @param elementDescriptor update this <code>ElementDescriptor</code> with the body text
          * @param context the <code>Context</code> against which the elements will be evaluated 
          */
          private void addRule( String path, ElementDescriptor elementDescriptor, Context context ) {
              BeanRule rule = new BeanRule( path + '/', elementDescriptor, context );
              addRule( path, rule, elementDescriptor, context );
          }
          
          /**
          * Safely add a rule with given path.
          *
          * @param path the digester path to add rule at
          * @param rule the <code>Rule</code> to add
          * @param elementDescriptor the <code>ElementDescriptor</code> 
          * associated with this rule
          * @param context the <code>Context</code> against which the elements 
          * will be evaluated        
          */
          private void addRule(
                              String path, 
                              Rule rule, 
                              ElementDescriptor elementDescriptor, 
                              Context context) {
              if ( add( path, rule ) ) {
                  // stop infinite recursion by allowing only one rule per path
                  addChildRules( path + '/', elementDescriptor, context );
              }
          }    
          
          /**
           * Add a rule at given path.
           *
           * @param path add rule at this path
           * @param rule the <code>Rule</code> to add
           *
           * @return true if this rule was successfully add at given path
           */
          private boolean add( String path, Rule rule ) {
              // only one bean rule allowed per path
              if ( ! rulesByPath.containsKey( path ) ) {
                  if ( log.isDebugEnabled() ) {
                      log.debug( "Added rule for path: " + path + " rule: " + rule );
                  }
                  rulesByPath.put( path, rule );
                  return true;
                  
              } else {
                  if ( log.isDebugEnabled() ) {
                      log.debug( "Ignoring duplicate digester rule for path: " 
                                  + path + " rule: " + rule );
                      log.debug( "New rule (not added): " + rule );
                      log.debug( "Existing rule:" + rulesByPath.get(path) );
                  }
              }
              return false;
          }
          
          /**
          * Rule that creates bean and updates methods.
          */
          private class BeanRule extends Rule {
              
              /** The descriptor of this element */
              private ElementDescriptor descriptor;
              /** The Context used when evaluating Updaters */
              private Context context;
              /** In this begin-end loop did we actually create a new bean */
              private boolean createdBean;
              /** The type of the bean to create */
              private Class beanClass;
              /** The prefix added to digester rules */
              private String pathPrefix;
              
              
              /** 
              * Constructor uses standard qualified name from <code>ElementDescriptor</code>.
              * 
              * @param descriptor the <code>ElementDescriptor</code> describing the element mapped
              * @param beanClass the <code>Class</code> to be created
              */
              public BeanRule( ElementDescriptor descriptor, Class beanClass ) {
                  this( descriptor.getQualifiedName() + "/", descriptor, beanClass  );
              }
              
              /**
              * Construct a rule for given bean at given path.
              *
              * @param pathPrefix the digester style path
              * @param descriptor the <code>ElementDescriptor</code> describing the element mapped
              * @param beanClass the <code>Class</code> to be created
              */
              public BeanRule(
                                      String pathPrefix,
                                      ElementDescriptor descriptor, 
                                      Class beanClass ) {
                  this( 
                          pathPrefix, 
                          descriptor, 
                          beanClass, 
                          new Context() );
              }
              
              /**
              * Construct a rule based on singular property type of <code>ElementDescriptor</code>.
              *
              * @param descriptor the <code>ElementDescriptor</code> describing the element mapped
              * @param context the <code>Context</code> to be used to evaluate expressions
              * @param pathPrefix the digester path prefix
              */
              public BeanRule(
                                      String pathPrefix,
                                      ElementDescriptor descriptor, 
                                      Context context ) {
                  this( 
                          pathPrefix,
                          descriptor, 
                          descriptor.getSingularPropertyType(), 
                          context );
              }
              
              /**
              * Base constructor (used by other constructors).
              *
              * @param descriptor the <code>ElementDescriptor</code> describing the element mapped
              * @param beanClass the <code>Class</code> of the bean to be created
              * @param context the <code>Context</code> to be used to evaluate expressions
              * @param pathPrefix the digester path prefix
              */
              private BeanRule(
                                      String pathPrefix, 
                                      ElementDescriptor descriptor, 
                                      Class beanClass,
                                      Context context ) {
                  this.descriptor = descriptor;        
                  this.context = context;
                  this.beanClass = beanClass;
                  this.pathPrefix = pathPrefix;
      
                  if (log.isTraceEnabled()) {
                      log.trace("Created bean create rule");
                      log.trace("Descriptor=" + descriptor);
                      log.trace("Class=" + beanClass);
                      log.trace("Path prefix=" + pathPrefix);
                  }
              }
                  
              // Rule interface
              //-------------------------------------------------------------------------    
              
              /**
              * Process the beginning of this element.
              *
              * @param attributes The attribute list of this element
              */
              public void begin(Attributes attributes) {
                  log.debug( "Called with descriptor: " + descriptor 
                              + " propertyType: " + descriptor.getPropertyType() );
                  
                  if (log.isTraceEnabled()) {
                      int attributesLength = attributes.getLength();
                      if (attributesLength > 0) {
                          log.trace("Attributes:");
                      }
                      for (int i=0, size=attributesLength; i<size; i++) {
                          log.trace("Local:" + attributes.getLocalName(i));
                          log.trace("URI:" + attributes.getURI(i));
                          log.trace("QName:" + attributes.getQName(i));
                      }
                  }
                  
          
                  
                  // XXX: if a single rule instance gets reused and nesting occurs
                  // XXX: we should probably use a stack of booleans to test if we created a bean
                  // XXX: or let digester take nulls, which would be easier for us ;-)
                  createdBean = false;
                          
                  Object instance = null;
                  if ( beanClass != null ) {
                      instance = createBean(attributes);
                      if ( instance != null ) {
                          createdBean = true;
          
                          context.setBean( instance );
                          digester.push(instance);
                          
                  
                          // if we are a reference to a type we should lookup the original
                          // as this ElementDescriptor will be 'hollow' 
                          // and have no child attributes/elements.
                          // XXX: this should probably be done by the NodeDescriptors...
                          ElementDescriptor typeDescriptor = getElementDescriptor( descriptor );
                          //ElementDescriptor typeDescriptor = descriptor;
                  
                          // iterate through all attributes        
                          AttributeDescriptor[] attributeDescriptors 
                              = typeDescriptor.getAttributeDescriptors();
                          if ( attributeDescriptors != null ) {
                              for ( int i = 0, size = attributeDescriptors.length; i < size; i++ ) {
                                  AttributeDescriptor attributeDescriptor = attributeDescriptors[i];
                                  
                                  // The following isn't really the right way to find the attribute
                                  // but it's quite robust.
                                  // The idea is that you try both namespace and local name first
                                  // and if this returns null try the qName.
                                  String value = attributes.getValue( 
                                      attributeDescriptor.getURI(),
                                      attributeDescriptor.getLocalName() 
                                  );
                                  
                                  if (value == null) {
                                      value = attributes.getValue(
                                          attributeDescriptor.getQualifiedName());
                                  }
                                  
                                  if (log.isTraceEnabled()) {
                                      log.trace("Attr URL:" + attributeDescriptor.getURI());
                                      log.trace(
                                                  "Attr LocalName:" 
                                                  + attributeDescriptor.getLocalName() );
                                      log.trace(value);
                                  }
                                  
                                  Updater updater = attributeDescriptor.getUpdater();
                                  log.trace(updater);
                                  if ( updater != null && value != null ) {
                                      updater.update( context, value );
                                  }
                              }
                          }
                          
                          // add bean for ID matching
                          if ( matchIDs ) {
                              // XXX need to support custom ID attribute names
                              // XXX i have a feeling that the current mechanism might need to change
                              // XXX so i'm leaving this till later
                              String id = attributes.getValue( "id" );
                              if ( id != null ) {
                                  getBeansById().put( id, instance );
                              }
                          }
                      }
                  }
              }
          
              /**
              * Process the end of this element.
              */
              public void end() {
                  if ( createdBean ) {
                      
                      // force any setters of the parent bean to be called for this new bean instance
                      Updater updater = descriptor.getUpdater();
                      Object instance = context.getBean();
          
                      Object top = digester.pop();
                      if (digester.getCount() == 0) {
                          context.setBean(null);
                      }else{
                          context.setBean( digester.peek() );
                      }
          
                      if ( updater != null ) {
                          if ( log.isDebugEnabled() ) {
                              log.debug( "Calling updater for: " + descriptor + " with: " 
                                  + instance + " on bean: " + context.getBean() );
                          }
                          updater.update( context, instance );
                      } else {
                          if ( log.isDebugEnabled() ) {
                              log.debug( "No updater for: " + descriptor + " with: " 
                                  + instance + " on bean: " + context.getBean() );
                          }
                      }
                  }
              }
          
              /** 
               * Tidy up.
               */
              public void finish() {
                  //
                  // Clear indexed beans so that we're ready to process next document
                  //
                  beansById.clear();
              }
          
          
              // Implementation methods
              //-------------------------------------------------------------------------    
              
              /** 
              * Factory method to create new bean instances 
              *
              * @param attributes the <code>Attributes</code> used to match <code>ID/IDREF</code>
              * @return the created bean
              */
              protected Object createBean(Attributes attributes) {
                  //
                  // See if we've got an IDREF
                  //
                  // XXX This should be customizable but i'm not really convinced by 
                  // XXX the existing system
                  // XXX maybe it's going to have to change so i'll use 'idref' for nows
                  //
                  if ( matchIDs ) {
                      String idref = attributes.getValue( "idref" );
                      if ( idref != null ) {
                          // XXX need to check up about ordering
                          // XXX this is a very simple system that assumes that 
                          // XXX id occurs before idrefs
                          // XXX would need some thought about how to implement a fuller system
                          log.trace( "Found IDREF" );
                          Object bean = getBeansById().get( idref );
                          if ( bean != null ) {
                              if (log.isTraceEnabled()) {
                                  log.trace( "Matched bean " + bean );
                              }
                              return bean;
                          }
                          log.trace( "No match found" );
                      }
                  }
                  
                  try {
                      if (log.isTraceEnabled()) {
                          log.trace( "Creating instance of " + beanClass );
                      }
                      return beanClass.newInstance();
                      
                  } catch (Exception e) {
                      log.warn( "Could not create instance of type: " + beanClass.getName() );
                      return null;
                  }
              }    
          
              /**
              * Get the map used to index beans (previously read in) by id.
              *
              * @return map indexing beans created by id
              */
              protected Map getBeansById() {
  
                  return beansById;
              }
              
              /**
              * Return something meaningful for logging.
              *
              * @return something useful for logging
              */
              public String toString() {
                  return "BeanRule [path prefix=" + pathPrefix + " descriptor=" + descriptor + "]";
              }
          }
      }
  }  
  
  
  
  
  1.9       +146 -5    jakarta-commons/betwixt/src/test/org/apache/commons/betwixt/TestBeanReader.java
  
  Index: TestBeanReader.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/betwixt/src/test/org/apache/commons/betwixt/TestBeanReader.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- TestBeanReader.java	30 Dec 2002 18:16:47 -0000	1.8
  +++ TestBeanReader.java	9 Feb 2003 22:27:18 -0000	1.9
  @@ -1,9 +1,61 @@
   /*
  - * Copyright (C) The Apache Software Foundation. All rights reserved.
  + * $Header$
  + * $Revision$
  + * $Date$
    *
  - * This software is published under the terms of the Apache Software License
  - * version 1.1, a copy of which has been included with this distribution in
  - * the LICENSE file.
  + * ====================================================================
  + *
  + * The Apache Software License, Version 1.1
  + *
  + * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
  + * reserved.
  + *
  + * Redistribution and use in source and binary forms, with or without
  + * modification, are permitted provided that the following conditions
  + * are met:
  + *
  + * 1. Redistributions of source code must retain the above copyright
  + *    notice, this list of conditions and the following disclaimer.
  + *
  + * 2. Redistributions in binary form must reproduce the above copyright
  + *    notice, this list of conditions and the following disclaimer in
  + *    the documentation and/or other materials provided with the
  + *    distribution.
  + *
  + * 3. The end-user documentation included with the redistribution, if
  + *    any, must include the following acknowlegement:
  + *       "This product includes software developed by the
  + *        Apache Software Foundation (http://www.apache.org/)."
  + *    Alternately, this acknowlegement may appear in the software itself,
  + *    if and wherever such third-party acknowlegements normally appear.
  + *
  + * 4. The names "The Jakarta Project", "Commons", and "Apache Software
  + *    Foundation" must not be used to endorse or promote products derived
  + *    from this software without prior written permission. For written
  + *    permission, please contact apache@apache.org.
  + *
  + * 5. Products derived from this software may not be called "Apache"
  + *    nor may "Apache" appear in their names without prior written
  + *    permission of the Apache Group.
  + *
  + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  + * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  + * SUCH DAMAGE.
  + * ====================================================================
  + *
  + * This software consists of voluntary contributions made by many
  + * individuals on behalf of the Apache Software Foundation.  For more
  + * information on the Apache Software Foundation, please see
  + * <http://www.apache.org/>.
    * 
    * $Id$
    */
  @@ -29,6 +81,11 @@
   import org.apache.commons.betwixt.io.BeanReader;
   import org.apache.commons.betwixt.io.BeanWriter;
   
  +import org.apache.commons.digester.Rule;
  +import org.apache.commons.digester.ExtendedBaseRules;
  +
  +import org.xml.sax.Attributes;
  +
   
   /** Test harness for the BeanReader
     *
  @@ -247,6 +304,90 @@
           finally {
               in.close();
           }   
  +    }
  +    
  +    /** Another test for reading wrapped collections */
  +    public void testWrapElements() throws Exception {
  +        ListOfNames listOfNames = new ListOfNames();
  +        listOfNames.addName( new NameBean("Martin") );
  +        
  +        String xml = "<ListOfNames><names><name name='Martin'/></names></ListOfNames>";
  +        
  +        BeanReader reader = new BeanReader();
  +        reader.getXMLIntrospector().setAttributesForPrimitives(true);
  +        reader.getXMLIntrospector().setWrapCollectionsInElement(true);
  +        
  +        reader.registerBeanClass(ListOfNames.class);
  +        ListOfNames newListOfNames = (ListOfNames) reader.parse(new StringReader(xml));
  +        
  +        assertEquals("Wrapped collection read fails", listOfNames, newListOfNames);
  +    }
  +    
  +    public void testSetDigesterRules() throws Exception {
  +        NameBean martinBean = new NameBean("Martin");
  +        ListOfNames listOfNames = new ListOfNames();
  +        listOfNames.addName( martinBean );
  +        
  +        String xml = "<ListOfNames><names><name name='Martin'/></names></ListOfNames>";
  +        
  +        BeanReader reader = new BeanReader();
  +        reader.setRules( new ExtendedBaseRules() );
  +        reader.getXMLIntrospector().setAttributesForPrimitives(true);
  +        reader.getXMLIntrospector().setWrapCollectionsInElement(true);
  +        
  +        TestRule ruleOne = new TestRule();
  +        TestRule ruleTwo = new TestRule();
  +        
  +        // add a test rule before the bean rules
  +        reader.addRule("!*/ListOfNames/names/name", ruleOne);
  +        reader.registerBeanClass(ListOfNames.class);
  +        // add a test rule after the bean rules
  +        reader.addRule("!*/ListOfNames/names/name", ruleTwo);
  +        
  +        ListOfNames newListOfNames = (ListOfNames) reader.parse(new StringReader(xml));
  +        
  +        reader.parse(new StringReader(xml));
  +        
  +        // test that the rules were called
  +        assertEquals("Rule one called", true , ruleOne.isCalled());
  +        assertEquals("Rule two called", true , ruleTwo.isCalled());
  +        
  +        // test that the top objects are correct
  +        assertEquals("Rule one digester top object", listOfNames , ruleOne.getTop());
  +        assertEquals("Rule two digester top object", martinBean , ruleTwo.getTop());
  +    }
  +    
  +    /** 
  +      * This is a member class since all classes starting with test 
  +      * will be run as test cases.
  +      */
  +    private class TestRule extends Rule {
  +        
  +        private String name;
  +        private boolean called = false;
  +        private Object top;
  +        
  +        public Object getTop() {
  +            return top;
  +        }
  +        
  +        public String getName() {
  +            return name;
  +        }
  +        
  +        public void setName(String name) {
  +            this.name = name;
  +        }	
  +        
  +        public boolean isCalled() {
  +            return called;
  +        }
  +        
  +        public void begin(Attributes attributes) {
  +            top = getDigester().peek();
  +            this.name = name;
  +            called = true;
  +        }
       }
   }
   
  
  
  
  1.1                  jakarta-commons/betwixt/src/test/org/apache/commons/betwixt/ListOfNames.java
  
  Index: ListOfNames.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/betwixt/src/test/org/apache/commons/betwixt/ListOfNames.java,v 1.1 2003/02/09 22:27:18 rdonkin Exp $
   * $Revision: 1.1 $
   * $Date: 2003/02/09 22:27:18 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Commons", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   * 
   * $Id: ListOfNames.java,v 1.1 2003/02/09 22:27:18 rdonkin Exp $
   */
  package org.apache.commons.betwixt;
  
  import java.util.List;
  import java.util.ArrayList;
  import java.util.Iterator;
  
  /** <p>A simple collection of <code>NameBean</code>'s.</p>
    *
    * @author <a href="mailto:rdonkin@apache.org">Robert Burrell Donkin</a>
    */
  public class ListOfNames {
      
      private List names = new ArrayList();
      
      public ListOfNames() {}
      
      public void addName(NameBean name) {
          names.add(name);
      }
      
      public List getNames() {
          return names;
      }
      
      public String toString() {  
          StringBuffer buffer = new StringBuffer("[");
          buffer.append("ListOfNames: ");
          boolean first = true;
          Iterator it = names.iterator();
          while ( it.hasNext() ) {
              if ( first ) {
                  first = !first;
              } else {
                  buffer.append(',');
              }
              buffer.append("'");
              buffer.append( ((NameBean) it.next()).getName() );
              buffer.append("'");
          }
          
          buffer.append("]");
          
          return buffer.toString();
      }
      
      public boolean equals( Object obj ) {
          if ( obj == null ) return false;
          if (obj instanceof ListOfNames) {
              ListOfNames otherList = (ListOfNames) obj;
              int count = 0;
              Iterator it = otherList.getNames().iterator();
              while (it.hasNext()) {
                  if (! names.get(count++).equals(it.next())) {
                      return false;
                  }
              }
                          
              return true;
          }
          
          return false;
      }
  }
  
  
  
  1.1                  jakarta-commons/betwixt/src/test/org/apache/commons/betwixt/NameBean.java
  
  Index: NameBean.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/betwixt/src/test/org/apache/commons/betwixt/NameBean.java,v 1.1 2003/02/09 22:27:18 rdonkin Exp $
   * $Revision: 1.1 $
   * $Date: 2003/02/09 22:27:18 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Commons", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   * 
   * $Id: NameBean.java,v 1.1 2003/02/09 22:27:18 rdonkin Exp $
   */
  package org.apache.commons.betwixt;
  
  /** <p><code>NameBean</code> very simple bean (useful to debug complex test cases).</p>
    *
    * @author <a href="mailto:rdonkin@apache.org">Robert Burrell Donkin</a>
    */
  public class NameBean {
      
      private String name;
      
      public NameBean() {}
      
      public NameBean(String name) 
      {
          setName(name);
      }
      
      public String getName() {
          return name;
      }
      
      public void setName(String name) {
          this.name = name;
      }
      
      public String toString() {  
          return "[" + this.getClass().getName() + ": name=" + name + "]";
      }
      
      public boolean equals( Object obj ) {
          if ( obj == null ) return false;
          if ( obj instanceof NameBean && getName() != null ) {
              return getName().equals(((NameBean) obj).getName());
          }
          
          return false;
      }
  }
  
  
  
  1.5       +17 -6     jakarta-commons/betwixt/src/test/org/apache/commons/betwixt/digester/TestIDRead.java
  
  Index: TestIDRead.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/betwixt/src/test/org/apache/commons/betwixt/digester/TestIDRead.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- TestIDRead.java	30 Dec 2002 18:16:48 -0000	1.4
  +++ TestIDRead.java	9 Feb 2003 22:27:18 -0000	1.5
  @@ -73,6 +73,13 @@
   import org.apache.commons.betwixt.io.BeanReader;
   import org.apache.commons.betwixt.io.BeanWriter;
   
  +//import org.apache.commons.logging.Log;
  +//import org.apache.commons.logging.impl.SimpleLog;
  +//import org.apache.commons.betwixt.expression.MethodUpdater;
  +//import org.apache.commons.betwixt.io.BeanCreateRule;
  +//import org.apache.commons.betwixt.io.BeanRuleSet;
  +
  +
   /** Test harness for ID-IDRef reading.
     *
     * @author Robert Burrell Donkin
  @@ -105,7 +112,7 @@
   //        SimpleLog log = new SimpleLog("[testSimpleRead:XMLIntrospectorHelper]");
   //        log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
   //        XMLIntrospectorHelper.setLog(log);
  -//        
  +        
   //        log = new SimpleLog("[testSimpleRead:MethodUpdater]");
   //        log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
   //        MethodUpdater.setLog(log);
  @@ -113,6 +120,10 @@
   //        log = new SimpleLog("[testSimpleRead:BeanCreateRule]");
   //        log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
   //        BeanCreateRule.setLog(log);
  +        
  +//        log = new SimpleLog("[testSimpleRead:BeanRuleSet]");
  +//        log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
  +//        BeanRuleSet.setLog(log);        
   
   //        log = new SimpleLog("[testSimpleRead:IDBean]");
   //        log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
  
  
  
  1.2       +16 -2     jakarta-commons/betwixt/src/test/org/apache/commons/betwixt/schema/Dbms.java
  
  Index: Dbms.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/betwixt/src/test/org/apache/commons/betwixt/schema/Dbms.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- Dbms.java	11 Jun 2002 16:05:21 -0000	1.1
  +++ Dbms.java	9 Feb 2003 22:27:18 -0000	1.2
  @@ -64,6 +64,7 @@
   
   import java.util.ArrayList;
   import java.util.List;
  +import java.util.Iterator;
   
   /**
    * @author <a href="mailto:martin@mvdb.net">Martin van den Bemt</a>
  @@ -113,12 +114,25 @@
           if (object instanceof Dbms) {
               Dbms dbms = (Dbms) object;
               if (dbms.getKind().equals(this.getKind())) {
  -                if (dbms.getDbids().equals(this.getDbids())) {
  -                    return true;
  +                int count = 0;
  +                Iterator it = dbms.getDbids().iterator();
  +                while ( it.hasNext() ) {
  +                    if (count >= dbidCollection.size() ) {
  +                        return false;
  +                    }
  +                    if (! it.next().equals( dbidCollection.get(count++) ) ) {
  +                        return false;
  +                    }
                   }
  +                
  +                return true;
               }
           }
           return false;
  +    }
  +    
  +    public String toString() {
  +        return "[DBMS: name='" + getKind() + "']";
       }
   }
   
  
  
  
  1.3       +16 -2     jakarta-commons/betwixt/src/test/org/apache/commons/betwixt/schema/PhysicalSchema.java
  
  Index: PhysicalSchema.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/betwixt/src/test/org/apache/commons/betwixt/schema/PhysicalSchema.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- PhysicalSchema.java	30 Dec 2002 18:16:47 -0000	1.2
  +++ PhysicalSchema.java	9 Feb 2003 22:27:18 -0000	1.3
  @@ -64,6 +64,7 @@
   
   import java.util.ArrayList;
   import java.util.List;
  +import java.util.Iterator;
   
   /**
    * @author <a href="mailto:martin@mvdb.net">Martin van den Bemt</a>
  @@ -113,12 +114,25 @@
           if (object instanceof PhysicalSchema) {
               PhysicalSchema schema = (PhysicalSchema) object;
               if (schema.getAutocreate().equals(this.getAutocreate())) {
  -                if (schema.getDbmss().equals(this.getDbmss())) {
  -                    return true;
  +                int count = 0;
  +                Iterator it = schema.getDbmss().iterator();
  +                while ( it.hasNext() ) {
  +                    if (count >= dbmsCollection.size() ) {
  +                        return false;
  +                    }
  +                    if (! it.next().equals( dbmsCollection.get(count++) ) ) {
  +                        return false;
  +                    }
                   }
  +                
  +                return true;
               }
           }
           return false;
       }
  +    
  +    public String toString() {
  +        return "[PhysicalSchema] autocreate=" + getAutocreate() + " dbmass=" + getDbmss();
  +    }	
   }
   
  
  
  
  1.6       +17 -2     jakarta-commons/betwixt/src/test/org/apache/commons/betwixt/schema/TestSchema.java
  
  Index: TestSchema.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/betwixt/src/test/org/apache/commons/betwixt/schema/TestSchema.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- TestSchema.java	30 Dec 2002 18:16:47 -0000	1.5
  +++ TestSchema.java	9 Feb 2003 22:27:18 -0000	1.6
  @@ -76,6 +76,8 @@
   import org.apache.commons.betwixt.strategy.DecapitalizeNameMapper;
   import org.apache.commons.betwixt.strategy.HyphenatedNameMapper;
   
  +//import org.apache.commons.logging.impl.SimpleLog;
  +//import org.apache.commons.betwixt.io.BeanRuleSet;
   
   /**
    * This will test betwixt on handling a different kind of xml file, without
  @@ -106,12 +108,23 @@
        */
       public void testCombinedRoundTrip()
       throws Exception
  -    {
  +    {	
  +//        SimpleLog log = new SimpleLog("[CombinedRoundTrip:BeanRuleSet]");
  +//        log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
  +//        BeanRuleSet.setLog(log);
  +        
  +//        log = new SimpleLog("[CombinedRoundTrip]");
  +//        log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
  +        
           BeanReader reader = createBeanReader();
  +        
           PhysicalSchema schema = (PhysicalSchema) reader.parse(
               getTestFileURL("src/test/org/apache/commons/betwixt/schema/schema.xml"));
           StringWriter buffer = new StringWriter();
           write(schema, buffer, true);
  +        
  +//        log.debug(buffer.getBuffer().toString());
  +        
           StringReader in = new StringReader(buffer.getBuffer().toString());
           reader = createBeanReader();
           XMLIntrospector intro = createXMLIntrospector();
  @@ -126,10 +139,12 @@
           registry.flush();
           // set the xmlIntrospector back to the reader
           reader.setXMLIntrospector(intro);
  +        reader.deregisterBeanClass(PhysicalSchema.class);
  +        reader.registerBeanClass(PhysicalSchema.class);
           PhysicalSchema schemaSecond = (PhysicalSchema) reader.parse(in);
           buffer.close();
           write(schema,buffer, true);
  -        assertEquals(schemaSecond, schema);
  +        assertEquals(schema, schemaSecond);
       }
       /**
        * Tests we can round trip from the XML -> bean -> XML -> bean.
  
  
  
  1.13      +31 -0     jakarta-commons/betwixt/xdocs/overview.xml
  
  Index: overview.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/betwixt/xdocs/overview.xml,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- overview.xml	29 Jan 2003 18:55:09 -0000	1.12
  +++ overview.xml	9 Feb 2003 22:27:18 -0000	1.13
  @@ -392,6 +392,37 @@
   
   </section>
   
  +<section name='Reading Beans (Advanced)'>
  +<subsection name='Adding Custom Digestion Rules'>
  +    <p>
  +    Betwixt builds on <code>Apache Digester</code> for bean reading. 
  +    <code>BeanReader</code> extends <code>Digester</code> 
  +    and this makes a wide range of functionality available.
  +    </p>
  +    
  +    <p>
  +    Digester uses <code>Rule</code>'s to specify the xml mapping (for more details see the 
  +    <a href='http://jakarta.apache.org/commons/digester.html'>Digester documentation</a>).
  +    Betwixt provides a custom ruleset (<code>BeanRuleSet</code>). This creates <code>Rule</code>'s that
  +    implement the standard Betwixt mapping for a class. <code>BeanReader.registerBeanClass</code> 
  +    uses this <code>RuleSet</code> to add these standard betwixt mapping <code>Rule</code>'s
  +    for the bean class.
  +    </p>
  +    
  +    <p>
  +    These standard Betwixt mapping rules can be integrated with other Digester <code>Rule</code>'s.
  +    <code>Rule</code>'s added before <code>registerBeanClass</code> is called will come before (in a 
  +    Digester sense) the standard betwixt <code>Rule</code>'s. Those added after will come afterwards.
  +    </p>
  +    
  +    <p>
  +    <strong>Note</strong> that care must be taken with the patterns for additional <code>Rule</code>'s.
  +    The standard Betwixt mapping will only work if all it's <code>Rule</code>'s are matched.
  +    </p>
  +    
  +</subsection>
  +</section>
  +
   <section name="Examples">
   <a name="simple-example"/>
   <subsection name='A Simple Example'>
  
  
  
  1.5       +10 -5     jakarta-commons/betwixt/xdocs/tasks.xml
  
  Index: tasks.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/betwixt/xdocs/tasks.xml,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- tasks.xml	28 Jan 2003 22:49:18 -0000	1.4
  +++ tasks.xml	9 Feb 2003 22:27:18 -0000	1.5
  @@ -149,11 +149,6 @@
                     files should use the <code>XMLBeanInfoDigester</code> classloader property which should
                     be set by the <code>XMLIntrospector</code>.
   		</li>
  -         <li>
  -                   Improve integration with digester. At the moment, bean reading is all or nothing. You 
  -                   either use betwixt to do everything or you use digester to specify rules. It'd be nice
  -                   to be able to mix and match.
  -                </li>
           <li>
               Create utility methods in BeanWriter to write stuff like prologs and doctype definitions to the 
               stream.
  @@ -190,6 +185,13 @@
                   Separated out basic xml utilty methods into a static utility class called XMLUtils.
                   This should allow them to be reused in isolation.
               </li>
  +            <li>
  +                <strong>Improved digester integration</strong>
  +                Improved integration with digester. <code>BeanRuleSet</code> is a digester ruleset
  +                which sets up all the rules required to digester a bean. When a bean is registered,
  +                a <code>BeanRuleSet</code> instance is used to set up the required rule on digester.
  +                Standard digester rules can be added before and after registration.
  +            </li>
           </ul>
       </subsection>
   </section>
  @@ -201,6 +203,9 @@
               </li>
               <li> 
                   <code>BeanWriter.escapeBodyValue()</code> moved into XMLUtils
  +            </li>
  +            <li> 
  +                <code>BeanCreateRule</code> has been replaced by BeanRuleSet
               </li>
           </ul>
       </subsection>
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Mime
View raw message