You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by dm...@apache.org on 2002/04/21 23:52:34 UTC

cvs commit: jakarta-commons/jxpath/src/test/org/apache/commons/jxpath JXPathTestCase.java TestBeanWithDOM.java TestFactory.java

dmitri      02/04/21 14:52:34

  Modified:    jxpath   .cvsignore
               jxpath/src/java/org/apache/commons/jxpath
                        AbstractFactory.java ClassFunctions.java
                        JXPathBasicBeanInfo.java JXPathBeanInfo.java
                        PackageFunctions.java
               jxpath/src/java/org/apache/commons/jxpath/functions
                        ConstructorFunction.java MethodFunction.java
               jxpath/src/java/org/apache/commons/jxpath/ri
                        EvalContext.java JXPathContextReferenceImpl.java
               jxpath/src/java/org/apache/commons/jxpath/ri/axes
                        AncestorContext.java AttributeContext.java
                        ChildContext.java DescendantContext.java
                        InitialContext.java NamespaceContext.java
                        ParentContext.java PrecedingOrFollowingContext.java
                        PredicateContext.java RootContext.java
                        SelfContext.java UnionContext.java
               jxpath/src/java/org/apache/commons/jxpath/ri/compiler
                        CoreFunction.java CoreOperation.java
                        ExtensionFunction.java NodeNameTest.java
                        TreeCompiler.java VariableReference.java
               jxpath/src/test/org/apache/commons/jxpath
                        JXPathTestCase.java TestBeanWithDOM.java
                        TestFactory.java
  Added:       jxpath/src/java/org/apache/commons/jxpath/ri QName.java
               jxpath/src/java/org/apache/commons/jxpath/ri/model
                        NodeIterator.java NodePointer.java
                        NodePointerFactory.java VariablePointer.java
                        package.html
               jxpath/src/java/org/apache/commons/jxpath/ri/model/beans
                        BeanAttributeIterator.java BeanPointer.java
                        BeanPointerFactory.java BeanPropertyPointer.java
                        CollectionPointer.java
                        CollectionPointerFactory.java DynamicPointer.java
                        DynamicPointerFactory.java
                        DynamicPropertyPointer.java
                        LangAttributePointer.java NullElementPointer.java
                        NullPointer.java NullPropertyPointer.java
                        PropertyIterator.java PropertyOwnerPointer.java
                        PropertyPointer.java package.html
               jxpath/src/java/org/apache/commons/jxpath/ri/model/container
                        ContainerPointer.java ContainerPointerFactory.java
                        package.html
               jxpath/src/java/org/apache/commons/jxpath/ri/model/dom
                        DOMAttributeIterator.java DOMAttributePointer.java
                        DOMNamespaceIterator.java DOMNodeIterator.java
                        DOMNodePointer.java DOMPointerFactory.java
                        NamespacePointer.java package.html
               jxpath/src/java/org/apache/commons/jxpath/util
                        TypeUtils.java ValueUtils.java
  Removed:     jxpath/src/java/org/apache/commons/jxpath/functions
                        Types.java
               jxpath/src/java/org/apache/commons/jxpath/ri/compiler
                        QName.java
               jxpath/src/java/org/apache/commons/jxpath/ri/pointers
                        BeanAttributeIterator.java BeanPointer.java
                        BeanPointerFactory.java BeanPropertyPointer.java
                        ContainerPointer.java ContainerPointerFactory.java
                        DOMAttributeIterator.java DOMAttributePointer.java
                        DOMNamespaceIterator.java DOMNodeIterator.java
                        DOMNodePointer.java DOMPointerFactory.java
                        DynamicPointer.java DynamicPointerFactory.java
                        DynamicPropertyPointer.java
                        LangAttributePointer.java NamespacePointer.java
                        NodeIterator.java NodePointer.java
                        NodePointerFactory.java NullElementPointer.java
                        NullPointer.java NullPropertyPointer.java
                        PropertyAccessHelper.java PropertyIterator.java
                        PropertyOwnerPointer.java PropertyPointer.java
                        VariablePointer.java package.html
  Log:
  Major refactoring
  
  Revision  Changes    Path
  1.2       +1 -0      jakarta-commons/jxpath/.cvsignore
  
  Index: .cvsignore
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/.cvsignore,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- .cvsignore	23 Aug 2001 00:46:57 -0000	1.1
  +++ .cvsignore	21 Apr 2002 21:52:31 -0000	1.2
  @@ -1,3 +1,4 @@
   build.properties
   dist
   target
  +bin
  
  
  
  1.2       +4 -12     jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/AbstractFactory.java
  
  Index: AbstractFactory.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/AbstractFactory.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- AbstractFactory.java	10 Apr 2002 03:40:19 -0000	1.1
  +++ AbstractFactory.java	21 Apr 2002 21:52:31 -0000	1.2
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/AbstractFactory.java,v 1.1 2002/04/10 03:40:19 dmitri Exp $
  - * $Revision: 1.1 $
  - * $Date: 2002/04/10 03:40:19 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/AbstractFactory.java,v 1.2 2002/04/21 21:52:31 dmitri Exp $
  + * $Revision: 1.2 $
  + * $Date: 2002/04/21 21:52:31 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -73,7 +73,7 @@
    * return true to indicate that the factory has successfully created the described object.
    *
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.1 $ $Date: 2002/04/10 03:40:19 $
  + * @version $Revision: 1.2 $ $Date: 2002/04/21 21:52:31 $
    */
   public abstract class AbstractFactory {
   
  @@ -82,7 +82,7 @@
        * to the factory to infer which one it is. If it is a collection, the
        * factory should check if the collection exists.  If not, it should create
        * the collection. Then it should create the index'th element of the collection
  -     * and return it.
  +     * and return true.
        * <p>
        * If the parameters describe an individual object, the factory should only
        * create an object if index == 0.
  @@ -91,14 +91,6 @@
        * the requested object.
        */
       public boolean createObject(JXPathContext context, Pointer pointer, Object parent, String name, int index){
  -        return false;
  -    }
  -
  -    /**
  -     * The factory should expand the collection to the specified size and return true. If
  -     * it cannot expand the collection, it should return false.
  -     */
  -    public boolean expandCollection(JXPathContext context, Pointer pointer, Object parent, String name, int size){
           return false;
       }
   
  
  
  
  1.3       +8 -7      jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ClassFunctions.java
  
  Index: ClassFunctions.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ClassFunctions.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- ClassFunctions.java	10 Apr 2002 03:40:19 -0000	1.2
  +++ ClassFunctions.java	21 Apr 2002 21:52:31 -0000	1.3
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ClassFunctions.java,v 1.2 2002/04/10 03:40:19 dmitri Exp $
  - * $Revision: 1.2 $
  - * $Date: 2002/04/10 03:40:19 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ClassFunctions.java,v 1.3 2002/04/21 21:52:31 dmitri Exp $
  + * $Revision: 1.3 $
  + * $Date: 2002/04/21 21:52:31 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -64,6 +64,7 @@
   import java.util.*;
   import java.lang.reflect.*;
   import org.apache.commons.jxpath.functions.*;
  +import org.apache.commons.jxpath.util.*;
   
   /**
    * Extension functions provided by a Java class.
  @@ -89,7 +90,7 @@
    * the method.
    *
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.2 $ $Date: 2002/04/10 03:40:19 $
  + * @version $Revision: 1.3 $ $Date: 2002/04/21 21:52:31 $
    */
   public class ClassFunctions implements Functions {
       private Class functionClass;
  @@ -119,18 +120,18 @@
           }
   
           if (name.equals("new")){
  -            Constructor constructor = Types.lookupConstructor(functionClass, parameters);
  +            Constructor constructor = TypeUtils.lookupConstructor(functionClass, parameters);
               if (constructor != null){
                   return new ConstructorFunction(constructor);
               }
           }
           else {
  -            Method method = Types.lookupStaticMethod(functionClass, name, parameters);
  +            Method method = TypeUtils.lookupStaticMethod(functionClass, name, parameters);
               if (method != null){
                   return new MethodFunction(method);
               }
   
  -            method = Types.lookupMethod(functionClass, name, parameters);
  +            method = TypeUtils.lookupMethod(functionClass, name, parameters);
               if (method != null){
                   return new MethodFunction(method);
               }
  
  
  
  1.3       +31 -4     jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/JXPathBasicBeanInfo.java
  
  Index: JXPathBasicBeanInfo.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/JXPathBasicBeanInfo.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- JXPathBasicBeanInfo.java	12 Apr 2002 02:28:06 -0000	1.2
  +++ JXPathBasicBeanInfo.java	21 Apr 2002 21:52:31 -0000	1.3
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/JXPathBasicBeanInfo.java,v 1.2 2002/04/12 02:28:06 dmitri Exp $
  - * $Revision: 1.2 $
  - * $Date: 2002/04/12 02:28:06 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/JXPathBasicBeanInfo.java,v 1.3 2002/04/21 21:52:31 dmitri Exp $
  + * $Revision: 1.3 $
  + * $Date: 2002/04/21 21:52:31 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -72,12 +72,13 @@
    * See java.beans.BeanInfo, java.beans.Introspector
    *
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.2 $ $Date: 2002/04/12 02:28:06 $
  + * @version $Revision: 1.3 $ $Date: 2002/04/21 21:52:31 $
    */
   public class JXPathBasicBeanInfo implements JXPathBeanInfo {
       private boolean atomic = false;
       private Class clazz;
       private PropertyDescriptor propertyDescriptors[];
  +    private String[] propertyNames;
       private Class dynamicPropertyHandlerClass;
   
       public JXPathBasicBeanInfo(Class clazz){
  @@ -135,6 +136,32 @@
               }
           }
           return propertyDescriptors;
  +    }
  +
  +    public PropertyDescriptor getPropertyDescriptor(String propertyName){
  +        if (propertyNames == null){
  +            PropertyDescriptor[] pds = getPropertyDescriptors();
  +            propertyNames = new String[pds.length];
  +            for (int i = 0; i < pds.length; i++){
  +                propertyNames[i] = pds[i].getName();
  +            }
  +        }
  +//        int inx = Arrays.binarySearch(propertyNames, propertyName);
  +//        if (inx < 0){
  +//            return null;
  +//        }
  +        for (int i = 0; i < propertyNames.length; i++){
  +            if (propertyNames[i] == propertyName){
  +                return propertyDescriptors[i];
  +            }
  +        }
  +
  +        for (int i = 0; i < propertyNames.length; i++){
  +            if (propertyNames[i].equals(propertyName)){
  +                return propertyDescriptors[i];
  +            }
  +        }
  +        return null;
       }
   
       /**
  
  
  
  1.3       +10 -4     jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/JXPathBeanInfo.java
  
  Index: JXPathBeanInfo.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/JXPathBeanInfo.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- JXPathBeanInfo.java	12 Apr 2002 02:28:06 -0000	1.2
  +++ JXPathBeanInfo.java	21 Apr 2002 21:52:31 -0000	1.3
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/JXPathBeanInfo.java,v 1.2 2002/04/12 02:28:06 dmitri Exp $
  - * $Revision: 1.2 $
  - * $Date: 2002/04/12 02:28:06 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/JXPathBeanInfo.java,v 1.3 2002/04/21 21:52:31 dmitri Exp $
  + * $Revision: 1.3 $
  + * $Date: 2002/04/21 21:52:31 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -75,7 +75,7 @@
    * "com.foo.BarXBeanInfo" and make it implement the JXPathBeanInfo interface.
    *
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.2 $ $Date: 2002/04/12 02:28:06 $
  + * @version $Revision: 1.3 $ $Date: 2002/04/21 21:52:31 $
    */
   public interface JXPathBeanInfo  {
   
  @@ -100,6 +100,12 @@
        * bean info object.  Returns null for atomic beans.
        */
       PropertyDescriptor[] getPropertyDescriptors();
  +
  +    /**
  +     * Returns a PropertyDescriptor for the specified name or null if there
  +     * is no such property.
  +     */
  +    PropertyDescriptor getPropertyDescriptor(String propertyName);
   
       /**
        * For dynamic objects, returns the class implementing
  
  
  
  1.3       +8 -7      jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/PackageFunctions.java
  
  Index: PackageFunctions.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/PackageFunctions.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- PackageFunctions.java	10 Apr 2002 03:40:19 -0000	1.2
  +++ PackageFunctions.java	21 Apr 2002 21:52:31 -0000	1.3
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/PackageFunctions.java,v 1.2 2002/04/10 03:40:19 dmitri Exp $
  - * $Revision: 1.2 $
  - * $Date: 2002/04/10 03:40:19 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/PackageFunctions.java,v 1.3 2002/04/21 21:52:31 dmitri Exp $
  + * $Revision: 1.3 $
  + * $Date: 2002/04/21 21:52:31 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -64,6 +64,7 @@
   import java.util.*;
   import java.lang.reflect.*;
   import org.apache.commons.jxpath.functions.*;
  +import org.apache.commons.jxpath.util.*;
   
   /**
    * Extension functions provided by Java classes.  The class prefix specified
  @@ -103,7 +104,7 @@
   
    *
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.2 $ $Date: 2002/04/10 03:40:19 $
  + * @version $Revision: 1.3 $ $Date: 2002/04/21 21:52:31 $
    */
   public class PackageFunctions implements Functions {
       private String classPrefix;
  @@ -147,7 +148,7 @@
                   }
               }
               if (target != null){
  -                Method method = Types.lookupMethod(target.getClass(), name, parameters);
  +                Method method = TypeUtils.lookupMethod(target.getClass(), name, parameters);
                   if (method != null){
                       return new MethodFunction(method);
                   }
  @@ -172,13 +173,13 @@
           }
   
           if (methodName.endsWith("new")){
  -            Constructor constructor = Types.lookupConstructor(functionClass, parameters);
  +            Constructor constructor = TypeUtils.lookupConstructor(functionClass, parameters);
               if (constructor != null){
                   return new ConstructorFunction(constructor);
               }
           }
           else {
  -            Method method = Types.lookupStaticMethod(functionClass, methodName, parameters);
  +            Method method = TypeUtils.lookupStaticMethod(functionClass, methodName, parameters);
               if (method != null){
                   return new MethodFunction(method);
               }
  
  
  
  1.3       +6 -5      jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/functions/ConstructorFunction.java
  
  Index: ConstructorFunction.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/functions/ConstructorFunction.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- ConstructorFunction.java	10 Apr 2002 03:40:19 -0000	1.2
  +++ ConstructorFunction.java	21 Apr 2002 21:52:31 -0000	1.3
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/functions/ConstructorFunction.java,v 1.2 2002/04/10 03:40:19 dmitri Exp $
  - * $Revision: 1.2 $
  - * $Date: 2002/04/10 03:40:19 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/functions/ConstructorFunction.java,v 1.3 2002/04/21 21:52:31 dmitri Exp $
  + * $Revision: 1.3 $
  + * $Date: 2002/04/21 21:52:31 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -64,12 +64,13 @@
   import java.util.*;
   import java.lang.reflect.*;
   import org.apache.commons.jxpath.*;
  +import org.apache.commons.jxpath.util.*;
   
   /**
    * An extension function that creates an instance using a constructor.
    *
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.2 $ $Date: 2002/04/10 03:40:19 $
  + * @version $Revision: 1.3 $ $Date: 2002/04/21 21:52:31 $
    */
   public class ConstructorFunction implements Function {
   
  @@ -99,7 +100,7 @@
                   args[0] = context;
               }
               for (int i = 0; i < parameters.length; i++){
  -                args[i + pi] = Types.convert(parameters[i], types[i]);
  +                args[i + pi] = TypeUtils.convert(parameters[i], types[i]);
               }
               return constructor.newInstance(args);
           }
  
  
  
  1.3       +8 -7      jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/functions/MethodFunction.java
  
  Index: MethodFunction.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/functions/MethodFunction.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- MethodFunction.java	10 Apr 2002 03:40:19 -0000	1.2
  +++ MethodFunction.java	21 Apr 2002 21:52:31 -0000	1.3
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/functions/MethodFunction.java,v 1.2 2002/04/10 03:40:19 dmitri Exp $
  - * $Revision: 1.2 $
  - * $Date: 2002/04/10 03:40:19 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/functions/MethodFunction.java,v 1.3 2002/04/21 21:52:31 dmitri Exp $
  + * $Revision: 1.3 $
  + * $Date: 2002/04/21 21:52:31 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -64,10 +64,11 @@
   import java.util.*;
   import java.lang.reflect.*;
   import org.apache.commons.jxpath.*;
  +import org.apache.commons.jxpath.util.*;
   
   /**
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.2 $ $Date: 2002/04/10 03:40:19 $
  + * @version $Revision: 1.3 $ $Date: 2002/04/21 21:52:31 $
    */
   public class MethodFunction implements Function {
   
  @@ -97,7 +98,7 @@
                       args[0] = context;
                   }
                   for (int i = 0; i < parameters.length; i++){
  -                    args[i + pi] = Types.convert(parameters[i], types[i + pi]);
  +                    args[i + pi] = TypeUtils.convert(parameters[i], types[i + pi]);
                   }
               }
               else {
  @@ -106,13 +107,13 @@
                   if (types.length >= 1 && ExpressionContext.class.isAssignableFrom(types[0])){
                       pi = 1;
                   }
  -                target = Types.convert(parameters[0], method.getDeclaringClass());
  +                target = TypeUtils.convert(parameters[0], method.getDeclaringClass());
                   args = new Object[parameters.length - 1 + pi];
                   if (pi == 1){
                       args[0] = context;
                   }
                   for (int i = 1; i < parameters.length; i++){
  -                    args[pi + i - 1] = Types.convert(parameters[i], types[i - 1]);
  +                    args[pi + i - 1] = TypeUtils.convert(parameters[i], types[i - 1]);
                   }
               }
   
  
  
  
  1.8       +197 -101  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/EvalContext.java
  
  Index: EvalContext.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/EvalContext.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- EvalContext.java	12 Apr 2002 02:28:06 -0000	1.7
  +++ EvalContext.java	21 Apr 2002 21:52:31 -0000	1.8
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/EvalContext.java,v 1.7 2002/04/12 02:28:06 dmitri Exp $
  - * $Revision: 1.7 $
  - * $Date: 2002/04/12 02:28:06 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/EvalContext.java,v 1.8 2002/04/21 21:52:31 dmitri Exp $
  + * $Revision: 1.8 $
  + * $Date: 2002/04/21 21:52:31 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -62,9 +62,9 @@
   package org.apache.commons.jxpath.ri;
   
   import org.apache.commons.jxpath.JXPathContext;
  -import org.apache.commons.jxpath.ri.Compiler;
   import org.apache.commons.jxpath.ri.compiler.*;
  -import org.apache.commons.jxpath.ri.pointers.*;
  +import org.apache.commons.jxpath.ri.model.*;
  +import org.apache.commons.jxpath.ri.model.beans.*;
   import org.apache.commons.jxpath.ri.axes.*;
   import org.apache.commons.jxpath.Function;
   import org.apache.commons.jxpath.ExpressionContext;
  @@ -79,7 +79,7 @@
    * implement behavior of various XPath axes: "child::", "parent::" etc.
    *
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.7 $ $Date: 2002/04/12 02:28:06 $
  + * @version $Revision: 1.8 $ $Date: 2002/04/21 21:52:31 $
    */
   public abstract class EvalContext {
       protected EvalContext parentContext;
  @@ -546,10 +546,10 @@
           }
   
           if (l instanceof NodePointer){
  -            l = ((NodePointer)l).getPrimitiveValue();
  +            l = ((NodePointer)l).getCanonicalValue();
           }
           if (r instanceof NodePointer){
  -            r = ((NodePointer)r).getPrimitiveValue();
  +            r = ((NodePointer)r).getCanonicalValue();
           }
   
           if (l instanceof Boolean || r instanceof Boolean){
  @@ -578,7 +578,7 @@
           while(nextSet()){
               while(next()){
                   NodePointer pointer = getCurrentNodePointer();
  -                set.add(pointer.getPrimitiveValue());
  +                set.add(pointer.getCanonicalValue());
               }
           }
           return set;
  @@ -625,7 +625,7 @@
               return "";
           }
           else if (object instanceof NodePointer){
  -            return stringValue(((NodePointer)object).getPrimitiveValue());
  +            return stringValue(((NodePointer)object).getCanonicalValue());
           }
           else if (object instanceof EvalContext){
               EvalContext ctx = (EvalContext)object;
  @@ -662,7 +662,7 @@
               return number(stringValue(object));
           }
           else if (object instanceof NodePointer){
  -            return number(((NodePointer)object).getPrimitiveValue());
  +            return number(((NodePointer)object).getCanonicalValue());
           }
   //        else if (object instanceof Node){
   //            System.err.println("HERE");
  @@ -696,7 +696,7 @@
               return value;
           }
           else if (object instanceof NodePointer){
  -            return doubleValue(((NodePointer)object).getPrimitiveValue());
  +            return doubleValue(((NodePointer)object).getCanonicalValue());
           }
           else if (object instanceof EvalContext){
               return doubleValue(stringValue(object));
  @@ -723,7 +723,7 @@
               return ((String)object).length() != 0;
           }
           else if (object instanceof NodePointer){
  -            return booleanValue(((NodePointer)object).getPrimitiveValue());
  +            return booleanValue(((NodePointer)object).getCanonicalValue());
           }
           return false;
       }
  @@ -745,114 +745,217 @@
           return evalSteps(new InitialContext(rootContext), path, firstMatch);
       }
   
  -
  -    private static final Object FAILURE = new Object();
  -
       /**
  -     * Attempts to evaluate a simple path without traversing contexts -
  -     * straight from a NodePointer to a NodePointer. This only works
  -     * in some cases though. Specifically, it works with JavaBeans
  -     * and objects with Dynamic Properties, but does not work with
  -     * DOM objects.
  +     * Walks a location path in a highly simplified fashion: from pointer to
  +     * pointer, no contexts.  This is only possible if the path consists of
  +     * simple steps like "/foo[3]" and is context-independent.
        */
  -    private Object tryBasicPath(NodePointer parentPointer, Step steps[]){
  +    private NodePointer interpretBasicPath(NodePointer parentPointer, Step steps[]){
           if (parentPointer == null){
  -            return FAILURE;
  +            return null;
           }
   
           NodePointer pointer = (NodePointer)parentPointer.clone();
  -        for (int i = 0; i < steps.length; i++){
  -            pointer = getPropertyPointer(pointer, ((NodeNameTest)steps[i].getNodeTest()).getNodeName().getName());
  -            if (pointer == null){
  -                return FAILURE;
  -            }
  +        while (pointer != null && !pointer.isNode()){
  +            pointer = pointer.getValuePointer();
  +        }
   
  -            Expression predicates[] = steps[i].getPredicates();
  -            if (predicates != null && predicates.length != 0){
  -                pointer = processBasicPredicates(pointer, predicates);
  +        for (int i = 0; i < steps.length; i++){
  +            Step step = steps[i];
  +            int defaultIndex = (i == steps.length - 1 ? -1 : 0);
  +            QName name = ((NodeNameTest)step.getNodeTest()).getNodeName();
  +            Expression predicates[] = step.getPredicates();
  +
  +            // The following complicated logic is designed to translate
  +            // an xpath like "foo[@name='x'][@name='y'][3]/bar/baz[4]" into
  +            // a sequence of "single steps", each of which takes a node pointer,
  +            // a name and an optional index and gets you another node pointer.
  +
  +            // Note: if the last step is not indexed, the default index used
  +            // for that very last step is "-1", that is "do not index at all",
  +            // not "0" as in all preceeding steps.
  +
  +            int count = (predicates == null ? 0 : predicates.length);
  +            if (count == 0){
  +                pointer = singleStep(pointer, name, defaultIndex, false);
               }
               else {
  -                // If we are in the middle of a path, we interpret
  -                // a component like "foo" as "foo[1]"
  -                if (i < steps.length - 1){
  -                    pointer.setIndex(0);
  +                Expression lastIndexPredicate = null;
  +                if (predicates[count - 1].
  +                            getEvaluationHint(CoreOperation.DYNAMIC_PROPERTY_ACCESS_HINT) == null){
  +                    lastIndexPredicate = predicates[count - 1];
  +                }
  +
  +                if (lastIndexPredicate != null){
  +                    int index = indexFromPredicate(lastIndexPredicate);
  +                    if (count == 1){
  +                        pointer = singleStep(pointer, name, index, false);
  +                    }
  +                    else {
  +                        pointer = singleStep(pointer, name, -1, false);
  +                        for (int j = 0; j < count - 1; j++){
  +                            String key = keyFromPredicate(predicates[j]);
  +                            if (j < count - 2){
  +                                pointer = singleStep(pointer, key, -1, true);
  +                            }
  +                            else {
  +                                pointer = singleStep(pointer, key, index, true);
  +                            }
  +                        }
  +                    }
  +                }
  +                else {
  +                    pointer = singleStep(pointer, name, -1, false);
  +                    for (int j = 0; j < count; j++){
  +                        String key = keyFromPredicate(predicates[j]);
  +                        if (j < count - 1){
  +                            pointer = singleStep(pointer, key, -1, true);
  +                        }
  +                        else {
  +                            pointer = singleStep(pointer, key, defaultIndex, true);
  +                        }
  +                    }
                   }
               }
           }
  -//        System.err.println("RETURNING: " + pointer);
           return pointer;
       }
   
  -    private NodePointer processBasicPredicates(NodePointer pointer, Expression[] predicates){
  -        if (predicates == null || predicates.length == 0){
  +    /**
  +     * Interprets predicates for the root expression of an Expression Path without creating
  +     * any intermediate contexts.  This is an option used for optimization when the path
  +     * has a simple structure and predicates are context-independent.
  +     */
  +    private NodePointer interpretBasicPredicates(NodePointer pointer, Expression predicates[]){
  +        if (predicates == null || predicates.length == 0 || pointer == null){
               return pointer;
           }
   
  -        for (int i = 0; pointer != null && i < predicates.length; i++){
  -            Expression expr = (Expression)predicates[i].getEvaluationHint(CoreOperation.DYNAMIC_PROPERTY_ACCESS_HINT);
  -            if (expr != null){
  -                String prop = stringValue(eval(expr, true));
  -                pointer = getPropertyPointer(pointer, prop);
  -                if (pointer instanceof NullPropertyPointer){
  -                    ((NullPropertyPointer)pointer).setDynamic(true);
  +        // The following complicated logic is designed to translate
  +        // an xpath like "$foo[@name='x'][@name='y'][3]" into
  +        // a sequence of "single steps", each of which takes a node pointer,
  +        // a name and an optional index and gets you another node pointer.
  +
  +        int count = predicates.length;
  +        Expression lastIndexPredicate = null;
  +        if (predicates[count - 1].
  +                    getEvaluationHint(CoreOperation.DYNAMIC_PROPERTY_ACCESS_HINT) == null){
  +            lastIndexPredicate = predicates[count - 1];
  +        }
  +
  +        if (lastIndexPredicate != null){
  +            int index = indexFromPredicate(lastIndexPredicate);
  +            if (count == 1){
  +                if (index >= 0 && index < pointer.getLength()){
  +                    pointer.setIndex(index);
  +                }
  +                else {
  +                    pointer = new NullElementPointer(pointer, index);
                   }
               }
               else {
  -                Object predicate = eval(predicates[i], true);
  -                if (predicate instanceof EvalContext){
  -                    predicate = ((EvalContext)predicate).getContextNodePointer();
  -                }
  -                if (predicate instanceof NodePointer){
  -                    predicate = ((NodePointer)predicate).getPrimitiveValue();
  -                }
  -                if (predicate == null){
  -                    throw new RuntimeException("Predicate is null: " + predicates[i]);
  -                }
  -                if (predicate instanceof Number){
  -                    int index = (int)(doubleValue(predicate) + 0.5);
  -                    if (index > 0 && index <= pointer.getLength()){
  -                        pointer.setIndex(index - 1);
  +                for (int j = 0; j < count - 1; j++){
  +                    String key = keyFromPredicate(predicates[j]);
  +                    if (j < count - 2){
  +                        pointer = singleStep(pointer, key, -1, true);
                       }
                       else {
  -                        pointer = new NullElementPointer(pointer, index - 1);
  +                        pointer = singleStep(pointer, key, index, true);
                       }
                   }
  -                else if (!booleanValue(predicate)){
  -                    pointer = null;
  +            }
  +        }
  +        else {
  +            for (int j = 0; j < count; j++){
  +                String key = keyFromPredicate(predicates[j]);
  +                if (j < count - 1){
  +                    pointer = singleStep(pointer, key, -1, true);
  +                }
  +                else {
  +                    pointer = singleStep(pointer, key, -1, true);
                   }
               }
           }
           return pointer;
       }
   
  -    private NodePointer getPropertyPointer(NodePointer ptr, String property){
  -        NodePointer pointer = ptr;
  -        while (true){
  -            if (pointer instanceof VariablePointer){
  -                pointer = ((VariablePointer)pointer).getValuePointer();
  +    /**
  +     * @param property can be either a name or a QName
  +     */
  +    private NodePointer singleStep(NodePointer parent, Object property, int index, boolean dynamic){
  +        if (parent instanceof PropertyOwnerPointer){
  +            PropertyPointer pointer = ((PropertyOwnerPointer)parent).getPropertyPointer();
  +            String name;
  +            if (property instanceof QName){
  +                name = ((QName)property).getName();
  +            }
  +            else {
  +                name = (String)property;
               }
  -            else if (pointer instanceof ContainerPointer){
  -                pointer = ((ContainerPointer)pointer).getValuePointer();
  +            pointer.setPropertyName(name);
  +            if (pointer instanceof NullPropertyPointer && dynamic){
  +                ((NullPropertyPointer)pointer).setDynamic(true);
  +            }
  +            if (index != -1){
  +                if (index >= 0 && index < pointer.getLength()){
  +                    pointer.setIndex(index);
  +                    return pointer.getValuePointer();
  +                }
  +                else {
  +                    return new NullElementPointer(pointer, index).getValuePointer();
  +                }
               }
               else {
  -                break;
  +                return pointer.getValuePointer();
  +            }
  +        }
  +        else {
  +            QName name;
  +            if (property instanceof QName){
  +                name = (QName)property;
  +            }
  +            else {
  +                name = new QName(null, (String)property);
  +            }
  +            NodeIterator it = parent.childIterator(new NodeNameTest(name), false, null);
  +            if (it != null && it.setPosition(index == -1 ? 1 : index + 1)){
  +                return it.getNodePointer();
  +            }
  +            else {
  +                PropertyPointer pointer = new NullPropertyPointer(parent);
  +                pointer.setPropertyName(name.toString());
  +                pointer.setIndex(index);
  +                return pointer.getValuePointer();
               }
           }
  +    }
   
  -        if (pointer != null && !(pointer instanceof PropertyOwnerPointer)){
  -            return null;
  +    private int indexFromPredicate(Expression predicate){
  +        Object value = eval(predicate, true);
  +        if (value instanceof EvalContext){
  +            value = ((EvalContext)value).getContextNodePointer();
  +        }
  +        if (value instanceof NodePointer){
  +            value = ((NodePointer)value).getCanonicalValue();
  +        }
  +        if (value == null){
  +            throw new RuntimeException("Predicate is null: " + value);
           }
   
  -        PropertyPointer prop;
  -        if (pointer != null){
  -            prop = ((PropertyOwnerPointer)pointer).getPropertyPointer();
  +        if (value instanceof Number){
  +            return (int)(doubleValue(value) + 0.5) - 1;
           }
  -        else {
  -            prop = new NullPropertyPointer(ptr);
  +        else if (booleanValue(value)){
  +            return 0;
           }
   
  -        prop.setPropertyName(property);
  -        return prop.childNodePointer();
  +        return -1;
  +    }
  +
  +    private String keyFromPredicate(Expression predicate){
  +        Expression expr = (Expression)predicate.
  +                getEvaluationHint(CoreOperation.DYNAMIC_PROPERTY_ACCESS_HINT);
  +        return stringValue(eval(expr));
       }
   
       /**
  @@ -877,21 +980,17 @@
           }
   
           Expression predicates[] = path.getPredicates();
  -        if (firstMatch){
  -            if (path.getEvaluationHint(ExpressionPath.BASIC_PREDICATES_HINT).equals(Boolean.TRUE)){
  -                EvalContext ctx = new InitialContext(context);
  -                NodePointer ptr = (NodePointer)ctx.getContextNodePointer();
  -                if (ptr != null &&
  -                        (ptr.getIndex() == NodePointer.WHOLE_COLLECTION ||
  -                         predicates == null || predicates.length == 0)){
  -                    NodePointer pointer = processBasicPredicates(ptr, predicates);
  -                    if (pointer != null){
  -                        Object result = tryBasicPath(pointer, path.getSteps());
  -                        if (result != FAILURE){
  -                            return result;
  -                        }
  -                    }
  -                }
  +
  +        if (firstMatch &&
  +                path.getEvaluationHint(ExpressionPath.BASIC_PREDICATES_HINT).equals(Boolean.TRUE) &&
  +                !(context instanceof UnionContext)){
  +            EvalContext ctx = context;
  +            NodePointer ptr = (NodePointer)ctx.getContextNodePointer();
  +            if (ptr != null &&
  +                    (ptr.getIndex() == NodePointer.WHOLE_COLLECTION ||
  +                     predicates == null || predicates.length == 0)){
  +                NodePointer pointer = interpretBasicPredicates(ptr, predicates);
  +                return interpretBasicPath(pointer, path.getSteps());
               }
           }
   
  @@ -909,15 +1008,12 @@
        */
       private Object evalSteps(EvalContext context, Path path, boolean firstMatch){
           Step steps[] = path.getSteps();
  +
           if (firstMatch && steps.length != 0){
               boolean basic = path.getEvaluationHint(Path.BASIC_PATH_HINT).equals(Boolean.TRUE);
               if (basic){
  -                EvalContext ctx = new InitialContext(context);
  -                NodePointer ptr = (NodePointer)ctx.getContextNodePointer();
  -                Object result = tryBasicPath(ptr, steps);
  -                if (result != FAILURE){
  -                    return result;
  -                }
  +                NodePointer ptr = (NodePointer)context.getContextNodePointer();
  +                return interpretBasicPath(ptr, steps);
               }
           }
   
  @@ -1074,7 +1170,7 @@
           int count = 0;
           Object value = eval(arg1, false);
           if (value instanceof NodePointer){
  -            value = ((NodePointer)value).getPrimitiveValue();
  +            value = ((NodePointer)value).getCanonicalValue();
           }
           if (value instanceof EvalContext){
               EvalContext ctx = (EvalContext)value;
  
  
  
  1.9       +54 -35    jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/JXPathContextReferenceImpl.java
  
  Index: JXPathContextReferenceImpl.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/JXPathContextReferenceImpl.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- JXPathContextReferenceImpl.java	12 Apr 2002 02:28:06 -0000	1.8
  +++ JXPathContextReferenceImpl.java	21 Apr 2002 21:52:32 -0000	1.9
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/JXPathContextReferenceImpl.java,v 1.8 2002/04/12 02:28:06 dmitri Exp $
  - * $Revision: 1.8 $
  - * $Date: 2002/04/12 02:28:06 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/JXPathContextReferenceImpl.java,v 1.9 2002/04/21 21:52:32 dmitri Exp $
  + * $Revision: 1.9 $
  + * $Date: 2002/04/21 21:52:32 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -62,25 +62,31 @@
   package org.apache.commons.jxpath.ri;
   
   
  +import java.lang.ref.SoftReference;
   import java.util.*;
   
  -import org.apache.commons.jxpath.Variables;
  -import org.apache.commons.jxpath.JXPathContext;
  -import org.apache.commons.jxpath.Pointer;
  -import org.apache.commons.jxpath.Functions;
   import org.apache.commons.jxpath.Function;
  +import org.apache.commons.jxpath.Functions;
  +import org.apache.commons.jxpath.JXPathContext;
   import org.apache.commons.jxpath.PackageFunctions;
  -import org.apache.commons.jxpath.ri.compiler.*;
  -import org.apache.commons.jxpath.ri.Compiler;
  -import org.apache.commons.jxpath.ri.pointers.*;
  -import org.apache.commons.jxpath.ri.EvalContext;
  -import org.apache.commons.jxpath.ri.axes.*;
  -import org.apache.commons.jxpath.functions.Types;
  -import java.lang.ref.SoftReference;
  +import org.apache.commons.jxpath.Pointer;
  +import org.apache.commons.jxpath.Variables;
  +import org.apache.commons.jxpath.ri.axes.RootContext;
  +import org.apache.commons.jxpath.ri.compiler.Expression;
  +import org.apache.commons.jxpath.ri.compiler.TreeCompiler;
  +import org.apache.commons.jxpath.ri.model.NodePointer;
  +import org.apache.commons.jxpath.ri.model.NodePointerFactory;
  +import org.apache.commons.jxpath.ri.model.VariablePointer;
  +import org.apache.commons.jxpath.ri.model.beans.BeanPointerFactory;
  +import org.apache.commons.jxpath.ri.model.beans.CollectionPointerFactory;
  +import org.apache.commons.jxpath.ri.model.beans.DynamicPointerFactory;
  +import org.apache.commons.jxpath.ri.model.container.ContainerPointerFactory;
  +import org.apache.commons.jxpath.ri.model.dom.DOMPointerFactory;
  +import org.apache.commons.jxpath.util.TypeUtils;
   
   /**
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.8 $ $Date: 2002/04/12 02:28:06 $
  + * @version $Revision: 1.9 $ $Date: 2002/04/21 21:52:32 $
    */
   public class JXPathContextReferenceImpl extends JXPathContext
   {
  @@ -92,12 +98,14 @@
       private static Vector nodeFactories = new Vector();
       private static NodePointerFactory nodeFactoryArray[] = null;
       static {
  +        nodeFactories.add(new CollectionPointerFactory());
           nodeFactories.add(new BeanPointerFactory());
           nodeFactories.add(new DynamicPointerFactory());
           nodeFactories.add(new DOMPointerFactory());
           nodeFactories.add(new ContainerPointerFactory());
           createNodeFactoryArray();
       }
  +    private NodePointer rootPointer;
   
       // The frequency of the cache cleanup
       private static final int CLEANUP_THRESHOLD = 500;
  @@ -168,7 +176,7 @@
       }
   
       private static void cleanupCache(){
  -        System.gc();
  +//        System.gc();
           Iterator it = compiled.entrySet().iterator();
           while (it.hasNext()){
               Map.Entry me = (Map.Entry)it.next();
  @@ -194,12 +202,8 @@
               EvalContext ctx = (EvalContext)result;
               result = ctx.getContextNodePointer();
           }
  -
  -//        if (result instanceof DOMNodePointer){
  -//            result = ((DOMNodePointer)result).stringValue();
  -//        }
           if (result instanceof NodePointer){
  -            result = ((NodePointer)result).getPrimitiveValue();
  +            result = ((NodePointer)result).getCanonicalValue();
           }
           return result;
       }
  @@ -211,12 +215,12 @@
       public Object getValue(String xpath, Class requiredType){
           Object value = getValue(xpath);
           if (value != null && requiredType != null){
  -            if (!Types.canConvert(value, requiredType)){
  +            if (!TypeUtils.canConvert(value, requiredType)){
                   throw new RuntimeException("Invalid expression type. '" + xpath +
                       "' returns " + value.getClass().getName() +
                       ". It cannot be converted to " + requiredType.getName());
               }
  -            value = Types.convert(value, requiredType);
  +            value = TypeUtils.convert(value, requiredType);
           }
           return value;
       }
  @@ -259,7 +263,7 @@
               return (Pointer)result;
           }
           else {
  -            return NodePointer.createNodePointer(null, result, getLocale());
  +            return NodePointer.newNodePointer(null, result, getLocale());
           }
       }
   
  @@ -283,6 +287,7 @@
               setValue(xpath, value, true);
           }
           catch (Throwable ex){
  +            ex.printStackTrace();
               throw new RuntimeException("Exception trying to create xpath " +
                       xpath + ". " + ex.getMessage());
           }
  @@ -301,15 +306,9 @@
               pointer = ctx.getContextNodePointer();
           }
           else {
  +            // This should never happen
               throw new RuntimeException("Cannot set value for xpath: " + xpath);
           }
  -//        Pointer p = pointer;
  -//        while (p != null){
  -//            System.err.println("PTR: " + p.getClass() + " " + p.asPath());
  -//            if (p instanceof NodePointer){
  -//                p = ((NodePointer)p).getParent();
  -//            }
  -//        }
           if (create){
               ((NodePointer)pointer).createPath(this, value);
           }
  @@ -334,16 +333,36 @@
               list.add((Pointer)result);
           }
           else {
  -            list.add(NodePointer.createNodePointer(null, result, getLocale()));
  +            list.add(NodePointer.newNodePointer(null, result, getLocale()));
           }
           return list;
       }
   
       private Object eval(String xpath, boolean firstMatchLookup) {
           Expression expr = compile(xpath);
  -        NodePointer pointer = NodePointer.createNodePointer(new QName(null, "root"), getContextBean(), getLocale());
  -        EvalContext ctx = new RootContext(this, pointer);
  -        return ctx.eval(expr, firstMatchLookup);
  +        return getRootContext().eval(expr, firstMatchLookup);
  +    }
  +
  +    private void printPointer(NodePointer pointer){
  +        Pointer p = pointer;
  +        while (p != null){
  +            System.err.println((p == pointer ? "POINTER: " : " PARENT: ") + p.getClass() + " " + p.asPath());
  +            if (p instanceof NodePointer){
  +                p = ((NodePointer)p).getParent();
  +            }
  +        }
  +    }
  +
  +    private synchronized NodePointer getRootPointer(){
  +        if (rootPointer == null){
  +            rootPointer = NodePointer.newNodePointer(new QName(null, "root"),
  +                getContextBean(), getLocale());
  +        }
  +        return rootPointer;
  +    }
  +
  +    private EvalContext getRootContext(){
  +        return new RootContext(this, getRootPointer());
       }
   
       private List resolveNodeSet(List list){
  
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/QName.java
  
  Index: QName.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/QName.java,v 1.1 2002/04/21 21:52:32 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:32 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri;
  
  import java.util.*;
  
  /**
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:32 $
   */
  public class QName {
      private String prefix;
      private String name;
  
      public QName(String prefix, String name){
          this.prefix = prefix;
          this.name = name;
      }
  
      public String getPrefix(){
          return prefix;
      }
  
      public String getName(){
          return name;
      }
  
      public String toString(){
          if (prefix != null){
              return prefix + ':' + name;
          }
          return name;
      }
  
      public int hashCode(){
          return name.hashCode();
      }
  
      public boolean equals(Object object){
          if (!(object instanceof QName)){
              return false;
          }
          if (this == object){
              return true;
          }
          QName that = (QName)object;
          if (!this.name.equals(that.name)){
              return false;
          }
  
          if ((this.prefix == null && that.prefix != null) ||
              (this.prefix != null && !this.prefix.equals(that.prefix))){
              return false;
          }
  
          return true;
      }
  
  }
  
  
  1.5       +15 -7     jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/AncestorContext.java
  
  Index: AncestorContext.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/AncestorContext.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- AncestorContext.java	10 Apr 2002 03:40:20 -0000	1.4
  +++ AncestorContext.java	21 Apr 2002 21:52:32 -0000	1.5
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/AncestorContext.java,v 1.4 2002/04/10 03:40:20 dmitri Exp $
  - * $Revision: 1.4 $
  - * $Date: 2002/04/10 03:40:20 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/AncestorContext.java,v 1.5 2002/04/21 21:52:32 dmitri Exp $
  + * $Revision: 1.5 $
  + * $Date: 2002/04/21 21:52:32 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -65,7 +65,7 @@
   import org.apache.commons.jxpath.ri.EvalContext;
   import org.apache.commons.jxpath.ri.compiler.*;
   import org.apache.commons.jxpath.*;
  -import org.apache.commons.jxpath.ri.pointers.*;
  +import org.apache.commons.jxpath.ri.model.*;
   
   import java.util.*;
   
  @@ -73,7 +73,7 @@
    * EvalContext that walks the "ancestor::" and "ancestor-or-self::" axes.
    *
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.4 $ $Date: 2002/04/10 03:40:20 $
  + * @version $Revision: 1.5 $ $Date: 2002/04/21 21:52:32 $
    */
   public class AncestorContext extends EvalContext {
       private NodeTest nodeTest;
  @@ -142,8 +142,16 @@
               }
           }
   
  -        currentNodePointer = currentNodePointer.getParent();
  +        while(true){
  +            currentNodePointer = currentNodePointer.getParent();
   
  -        return currentNodePointer != null && currentNodePointer.testNode(nodeTest);
  +            if (currentNodePointer == null){
  +                return false;
  +            }
  +
  +            if (currentNodePointer.testNode(nodeTest)){
  +                return true;
  +            }
  +        }
       }
   }
  
  
  
  1.4       +6 -5      jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/AttributeContext.java
  
  Index: AttributeContext.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/AttributeContext.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- AttributeContext.java	10 Apr 2002 03:40:20 -0000	1.3
  +++ AttributeContext.java	21 Apr 2002 21:52:32 -0000	1.4
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/AttributeContext.java,v 1.3 2002/04/10 03:40:20 dmitri Exp $
  - * $Revision: 1.3 $
  - * $Date: 2002/04/10 03:40:20 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/AttributeContext.java,v 1.4 2002/04/21 21:52:32 dmitri Exp $
  + * $Revision: 1.4 $
  + * $Date: 2002/04/21 21:52:32 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -61,9 +61,10 @@
    */
   package org.apache.commons.jxpath.ri.axes;
   
  +import org.apache.commons.jxpath.ri.*;
   import org.apache.commons.jxpath.ri.EvalContext;
   import org.apache.commons.jxpath.ri.compiler.*;
  -import org.apache.commons.jxpath.ri.pointers.*;
  +import org.apache.commons.jxpath.ri.model.*;
   
   import java.util.*;
   
  @@ -71,7 +72,7 @@
    * EvalContext that walks the "attribute::" axis.
    *
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.3 $ $Date: 2002/04/10 03:40:20 $
  + * @version $Revision: 1.4 $ $Date: 2002/04/21 21:52:32 $
    */
   public class AttributeContext extends EvalContext {
       private NodeTest nodeTest;
  
  
  
  1.5       +12 -7     jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/ChildContext.java
  
  Index: ChildContext.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/ChildContext.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- ChildContext.java	10 Apr 2002 03:40:20 -0000	1.4
  +++ ChildContext.java	21 Apr 2002 21:52:32 -0000	1.5
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/ChildContext.java,v 1.4 2002/04/10 03:40:20 dmitri Exp $
  - * $Revision: 1.4 $
  - * $Date: 2002/04/10 03:40:20 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/ChildContext.java,v 1.5 2002/04/21 21:52:32 dmitri Exp $
  + * $Revision: 1.5 $
  + * $Date: 2002/04/21 21:52:32 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -64,7 +64,7 @@
   import org.apache.commons.jxpath.*;
   import org.apache.commons.jxpath.ri.Compiler;
   import org.apache.commons.jxpath.ri.compiler.*;
  -import org.apache.commons.jxpath.ri.pointers.*;
  +import org.apache.commons.jxpath.ri.model.*;
   import org.apache.commons.jxpath.ri.EvalContext;
   
   import java.lang.reflect.*;
  @@ -76,7 +76,7 @@
    * "preceding-sibling::" axes.
    *
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.4 $ $Date: 2002/04/10 03:40:20 $
  + * @version $Revision: 1.5 $ $Date: 2002/04/21 21:52:32 $
    */
   public class ChildContext extends EvalContext {
       private NodeTest nodeTest;
  @@ -158,10 +158,15 @@
               return;
           }
           if (startFromParentLocation){
  -            iterator = parent.siblingIterator(nodeTest, reverse);
  +            NodePointer pointer = parent.getParent();
  +            while (pointer != null && !pointer.isNode()){
  +                pointer = pointer.getParent();
  +            }
  +
  +            iterator = pointer.childIterator(nodeTest, reverse, parent);
           }
           else {
  -            iterator = parent.childIterator(nodeTest, reverse);
  +            iterator = parent.childIterator(nodeTest, reverse, null);
           }
       }
   }
  
  
  
  1.5       +7 -7      jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/DescendantContext.java
  
  Index: DescendantContext.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/DescendantContext.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- DescendantContext.java	10 Apr 2002 03:40:20 -0000	1.4
  +++ DescendantContext.java	21 Apr 2002 21:52:32 -0000	1.5
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/DescendantContext.java,v 1.4 2002/04/10 03:40:20 dmitri Exp $
  - * $Revision: 1.4 $
  - * $Date: 2002/04/10 03:40:20 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/DescendantContext.java,v 1.5 2002/04/21 21:52:32 dmitri Exp $
  + * $Revision: 1.5 $
  + * $Date: 2002/04/21 21:52:32 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -64,7 +64,7 @@
   import org.apache.commons.jxpath.ri.Compiler;
   import org.apache.commons.jxpath.ri.compiler.*;
   import org.apache.commons.jxpath.*;
  -import org.apache.commons.jxpath.ri.pointers.*;
  +import org.apache.commons.jxpath.ri.model.*;
   import org.apache.commons.jxpath.ri.EvalContext;
   import java.util.*;
   
  @@ -73,7 +73,7 @@
    * axes.
    *
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.4 $ $Date: 2002/04/10 03:40:20 $
  + * @version $Revision: 1.5 $ $Date: 2002/04/21 21:52:32 $
    */
   public class DescendantContext extends EvalContext {
       private NodeTest nodeTest;
  @@ -123,7 +123,7 @@
               currentNodePointer = parentContext.getCurrentNodePointer();
               if (currentNodePointer != null){
                   if (!currentNodePointer.isLeaf()){
  -                    stack.push(currentNodePointer.childIterator(null, false));
  +                    stack.push(currentNodePointer.childIterator(null, false, null));
                   }
                   if (includeSelf){
                       if (currentNodePointer.testNode(nodeTest)){
  @@ -139,7 +139,7 @@
               if (it.setPosition(it.getPosition() + 1)){
                   currentNodePointer = it.getNodePointer();
                   if (!currentNodePointer.isLeaf()){
  -                    stack.push(currentNodePointer.childIterator(null, false));
  +                    stack.push(currentNodePointer.childIterator(null, false, null));
                   }
                   if (currentNodePointer.testNode(nodeTest)){
                       position++;
  
  
  
  1.4       +5 -5      jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/InitialContext.java
  
  Index: InitialContext.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/InitialContext.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- InitialContext.java	10 Apr 2002 03:40:20 -0000	1.3
  +++ InitialContext.java	21 Apr 2002 21:52:32 -0000	1.4
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/InitialContext.java,v 1.3 2002/04/10 03:40:20 dmitri Exp $
  - * $Revision: 1.3 $
  - * $Date: 2002/04/10 03:40:20 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/InitialContext.java,v 1.4 2002/04/21 21:52:32 dmitri Exp $
  + * $Revision: 1.4 $
  + * $Date: 2002/04/21 21:52:32 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -64,7 +64,7 @@
   import org.apache.commons.jxpath.Pointer;
   import org.apache.commons.jxpath.ri.Compiler;
   import org.apache.commons.jxpath.ri.compiler.*;
  -import org.apache.commons.jxpath.ri.pointers.*;
  +import org.apache.commons.jxpath.ri.model.*;
   import org.apache.commons.jxpath.ri.EvalContext;
   import java.util.*;
   
  @@ -74,7 +74,7 @@
    * on to the parent context.
    *
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.3 $ $Date: 2002/04/10 03:40:20 $
  + * @version $Revision: 1.4 $ $Date: 2002/04/21 21:52:32 $
    */
   public class InitialContext extends EvalContext {
       private boolean startedSet = false;
  
  
  
  1.3       +6 -5      jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/NamespaceContext.java
  
  Index: NamespaceContext.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/NamespaceContext.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- NamespaceContext.java	10 Apr 2002 03:40:20 -0000	1.2
  +++ NamespaceContext.java	21 Apr 2002 21:52:32 -0000	1.3
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/NamespaceContext.java,v 1.2 2002/04/10 03:40:20 dmitri Exp $
  - * $Revision: 1.2 $
  - * $Date: 2002/04/10 03:40:20 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/NamespaceContext.java,v 1.3 2002/04/21 21:52:32 dmitri Exp $
  + * $Revision: 1.3 $
  + * $Date: 2002/04/21 21:52:32 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -61,9 +61,10 @@
    */
   package org.apache.commons.jxpath.ri.axes;
   
  +import org.apache.commons.jxpath.ri.*;
   import org.apache.commons.jxpath.ri.EvalContext;
   import org.apache.commons.jxpath.ri.compiler.*;
  -import org.apache.commons.jxpath.ri.pointers.*;
  +import org.apache.commons.jxpath.ri.model.*;
   
   import java.util.*;
   
  @@ -71,7 +72,7 @@
    * EvalContext that walks the "namespace::" axis.
    *
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.2 $ $Date: 2002/04/10 03:40:20 $
  + * @version $Revision: 1.3 $ $Date: 2002/04/21 21:52:32 $
    */
   public class NamespaceContext extends EvalContext {
       private NodeTest nodeTest;
  
  
  
  1.4       +8 -5      jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/ParentContext.java
  
  Index: ParentContext.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/ParentContext.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- ParentContext.java	10 Apr 2002 03:40:20 -0000	1.3
  +++ ParentContext.java	21 Apr 2002 21:52:32 -0000	1.4
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/ParentContext.java,v 1.3 2002/04/10 03:40:20 dmitri Exp $
  - * $Revision: 1.3 $
  - * $Date: 2002/04/10 03:40:20 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/ParentContext.java,v 1.4 2002/04/21 21:52:32 dmitri Exp $
  + * $Revision: 1.4 $
  + * $Date: 2002/04/21 21:52:32 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -64,7 +64,7 @@
   import org.apache.commons.jxpath.ri.Compiler;
   import org.apache.commons.jxpath.ri.compiler.*;
   import org.apache.commons.jxpath.*;
  -import org.apache.commons.jxpath.ri.pointers.*;
  +import org.apache.commons.jxpath.ri.model.*;
   import org.apache.commons.jxpath.ri.EvalContext;
   
   import java.util.*;
  @@ -73,7 +73,7 @@
    * EvalContext that walks the "parent::" axis.
    *
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.3 $ $Date: 2002/04/10 03:40:20 $
  + * @version $Revision: 1.4 $ $Date: 2002/04/21 21:52:32 $
    */
   public class ParentContext extends EvalContext {
       private NodeTest nodeTest;
  @@ -128,6 +128,9 @@
           setStarted = true;
           NodePointer thisLocation = parentContext.getCurrentNodePointer();
           currentNodePointer = thisLocation.getParent();
  +        while (currentNodePointer != null && !currentNodePointer.isNode()){
  +            currentNodePointer = currentNodePointer.getParent();
  +        }
           return currentNodePointer != null && currentNodePointer.testNode(nodeTest);
       }
   }
  
  
  
  1.5       +30 -12    jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/PrecedingOrFollowingContext.java
  
  Index: PrecedingOrFollowingContext.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/PrecedingOrFollowingContext.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- PrecedingOrFollowingContext.java	10 Apr 2002 03:40:20 -0000	1.4
  +++ PrecedingOrFollowingContext.java	21 Apr 2002 21:52:32 -0000	1.5
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/PrecedingOrFollowingContext.java,v 1.4 2002/04/10 03:40:20 dmitri Exp $
  - * $Revision: 1.4 $
  - * $Date: 2002/04/10 03:40:20 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/PrecedingOrFollowingContext.java,v 1.5 2002/04/21 21:52:32 dmitri Exp $
  + * $Revision: 1.5 $
  + * $Date: 2002/04/21 21:52:32 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -64,7 +64,8 @@
   import org.apache.commons.jxpath.*;
   import org.apache.commons.jxpath.ri.Compiler;
   import org.apache.commons.jxpath.ri.compiler.*;
  -import org.apache.commons.jxpath.ri.pointers.*;
  +import org.apache.commons.jxpath.ri.model.*;
  +import org.apache.commons.jxpath.ri.model.beans.*;
   import org.apache.commons.jxpath.ri.EvalContext;
   import java.lang.reflect.*;
   import java.util.*;
  @@ -74,7 +75,7 @@
    * EvalContext that walks the "preceding::" and "following::" axes.
    *
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.4 $ $Date: 2002/04/10 03:40:20 $
  + * @version $Revision: 1.5 $ $Date: 2002/04/21 21:52:32 $
    */
   public class PrecedingOrFollowingContext extends EvalContext {
       private NodeTest nodeTest;
  @@ -121,18 +122,25 @@
           if (!setStarted){
               setStarted = true;
               currentRootLocation = parentContext.getCurrentNodePointer();
  -            // TBD: check type
  -            stack.push(currentRootLocation.siblingIterator(null, reverse));
  +            NodePointer parent = getMaterialPointer(currentRootLocation.getParent());
  +            if (parent != null){
  +                // TBD: check type
  +                stack.push(parent.childIterator(null, reverse, currentRootLocation));
  +            }
           }
   
           while (true){
               if (stack.isEmpty()){
  -                currentRootLocation = currentRootLocation.getParent();
  +                currentRootLocation = getMaterialPointer(currentRootLocation.getParent());
  +
                   if (currentRootLocation == null || currentRootLocation.isRoot()){
                       break;
                   }
  -                // TBD: check type
  -                stack.push(currentRootLocation.siblingIterator(null, reverse));
  +
  +                NodePointer parent = getMaterialPointer(currentRootLocation.getParent());
  +                if (parent != null){
  +                    stack.push(parent.childIterator(null, reverse, currentRootLocation));
  +                }
               }
   
               while (!stack.isEmpty()){
  @@ -141,7 +149,7 @@
                       if (it.setPosition(it.getPosition() + 1)){
                           currentNodePointer = it.getNodePointer();
                           if (!currentNodePointer.isLeaf()){
  -                            stack.push(currentNodePointer.childIterator(null, reverse));
  +                            stack.push(currentNodePointer.childIterator(null, reverse, null));
                           }
                           if (currentNodePointer.testNode(nodeTest)){
                               super.setPosition(getCurrentPosition() + 1);
  @@ -158,7 +166,7 @@
                       if (it.setPosition(it.getPosition() + 1)){
                           currentNodePointer = it.getNodePointer();
                           if (!currentNodePointer.isLeaf()){
  -                            stack.push(currentNodePointer.childIterator(null, reverse));
  +                            stack.push(currentNodePointer.childIterator(null, reverse, null));
                           }
                           else if (currentNodePointer.testNode(nodeTest)){
                               super.setPosition(getCurrentPosition() + 1);
  @@ -180,5 +188,15 @@
               }
           }
           return false;
  +    }
  +
  +    /**
  +     * If the pointer is auxiliary, return the parent; otherwise - the pointer itself
  +     */
  +    private NodePointer getMaterialPointer(NodePointer pointer){
  +        while (pointer != null && !pointer.isNode()){
  +            pointer = pointer.getParent();
  +        }
  +        return pointer;
       }
   }
  
  
  
  1.5       +19 -9     jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/PredicateContext.java
  
  Index: PredicateContext.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/PredicateContext.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- PredicateContext.java	10 Apr 2002 03:40:20 -0000	1.4
  +++ PredicateContext.java	21 Apr 2002 21:52:32 -0000	1.5
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/PredicateContext.java,v 1.4 2002/04/10 03:40:20 dmitri Exp $
  - * $Revision: 1.4 $
  - * $Date: 2002/04/10 03:40:20 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/PredicateContext.java,v 1.5 2002/04/21 21:52:32 dmitri Exp $
  + * $Revision: 1.5 $
  + * $Date: 2002/04/21 21:52:32 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -66,14 +66,15 @@
   
   import org.apache.commons.jxpath.ri.compiler.*;
   import org.apache.commons.jxpath.ri.Compiler;
  -import org.apache.commons.jxpath.ri.pointers.*;
  +import org.apache.commons.jxpath.ri.model.*;
  +import org.apache.commons.jxpath.ri.model.beans.*;
   import org.apache.commons.jxpath.ri.EvalContext;
   
   /**
    * EvalContext that checks predicates.
    *
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.4 $ $Date: 2002/04/10 03:40:20 $
  + * @version $Revision: 1.5 $ $Date: 2002/04/21 21:52:32 $
    */
   public class PredicateContext extends EvalContext {
       private Expression expression;
  @@ -96,9 +97,9 @@
               if (setupDynamicPropertyPointer()){
                   Object pred = parentContext.eval(dynamicPropertyNameExpression);
                   if (pred instanceof NodePointer){
  -                    pred = ((NodePointer)pred).getValue();
  +                    pred = ((NodePointer)pred).getCanonicalValue();
                   }
  -                dynamicPropertyPointer.setPropertyName(String.valueOf(pred));
  +                dynamicPropertyPointer.setPropertyName(stringValue(pred));
                   done = true;
                   return true;
               }
  @@ -135,7 +136,7 @@
           if (!(parent instanceof PropertyOwnerPointer)){
               return false;
           }
  -        dynamicPropertyPointer = ((PropertyOwnerPointer)parentContext.getCurrentNodePointer()).getPropertyPointer();
  +        dynamicPropertyPointer = ((PropertyOwnerPointer)parent).getPropertyPointer();
           return true;
       }
   
  @@ -164,6 +165,15 @@
       }
   
       public boolean setPosition(int position){
  -        return false;
  +        if (this.position > position){
  +            reset();
  +        }
  +
  +        while (this.position < position){
  +            if (!next()){
  +                return false;
  +            }
  +        }
  +        return true;
       }
   }
  
  
  
  1.5       +7 -6      jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/RootContext.java
  
  Index: RootContext.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/RootContext.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- RootContext.java	10 Apr 2002 03:40:20 -0000	1.4
  +++ RootContext.java	21 Apr 2002 21:52:32 -0000	1.5
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/RootContext.java,v 1.4 2002/04/10 03:40:20 dmitri Exp $
  - * $Revision: 1.4 $
  - * $Date: 2002/04/10 03:40:20 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/RootContext.java,v 1.5 2002/04/21 21:52:32 dmitri Exp $
  + * $Revision: 1.5 $
  + * $Date: 2002/04/21 21:52:32 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -64,7 +64,8 @@
   import org.apache.commons.jxpath.JXPathContext;
   import org.apache.commons.jxpath.ri.Compiler;
   import org.apache.commons.jxpath.ri.compiler.*;
  -import org.apache.commons.jxpath.ri.pointers.*;
  +import org.apache.commons.jxpath.ri.model.*;
  +import org.apache.commons.jxpath.ri.*;
   import org.apache.commons.jxpath.ri.EvalContext;
   import org.apache.commons.jxpath.ri.JXPathContextReferenceImpl;
   import org.apache.commons.jxpath.Function;
  @@ -74,7 +75,7 @@
    * EvalContext that is used to hold the root node for the path traversal.
    *
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.4 $ $Date: 2002/04/10 03:40:20 $
  + * @version $Revision: 1.5 $ $Date: 2002/04/21 21:52:32 $
    */
   public class RootContext extends EvalContext {
       private boolean startedSet = false;
  @@ -129,7 +130,7 @@
       }
   
       public EvalContext getConstantContext(Object constant){
  -        NodePointer pointer = NodePointer.createNodePointer(new QName(null, ""), constant, null);
  +        NodePointer pointer = NodePointer.newNodePointer(new QName(null, ""), constant, null);
           return new InitialContext(new RootContext(parent, pointer));
       }
   
  
  
  
  1.4       +5 -5      jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/SelfContext.java
  
  Index: SelfContext.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/SelfContext.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- SelfContext.java	10 Apr 2002 03:40:20 -0000	1.3
  +++ SelfContext.java	21 Apr 2002 21:52:32 -0000	1.4
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/SelfContext.java,v 1.3 2002/04/10 03:40:20 dmitri Exp $
  - * $Revision: 1.3 $
  - * $Date: 2002/04/10 03:40:20 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/SelfContext.java,v 1.4 2002/04/21 21:52:32 dmitri Exp $
  + * $Revision: 1.4 $
  + * $Date: 2002/04/21 21:52:32 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -65,7 +65,7 @@
   import org.apache.commons.jxpath.Pointer;
   import org.apache.commons.jxpath.ri.Compiler;
   import org.apache.commons.jxpath.ri.compiler.*;
  -import org.apache.commons.jxpath.ri.pointers.*;
  +import org.apache.commons.jxpath.ri.model.*;
   import org.apache.commons.jxpath.ri.EvalContext;
   
   import java.util.*;
  @@ -74,7 +74,7 @@
    * EvalContext that returns the current node from the parent context if the test succeeds.
    *
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.3 $ $Date: 2002/04/10 03:40:20 $
  + * @version $Revision: 1.4 $ $Date: 2002/04/21 21:52:32 $
    */
   public class SelfContext extends EvalContext {
       private NodeTest nodeTest;
  
  
  
  1.4       +5 -5      jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/UnionContext.java
  
  Index: UnionContext.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/UnionContext.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- UnionContext.java	10 Apr 2002 03:40:20 -0000	1.3
  +++ UnionContext.java	21 Apr 2002 21:52:32 -0000	1.4
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/UnionContext.java,v 1.3 2002/04/10 03:40:20 dmitri Exp $
  - * $Revision: 1.3 $
  - * $Date: 2002/04/10 03:40:20 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/axes/UnionContext.java,v 1.4 2002/04/21 21:52:32 dmitri Exp $
  + * $Revision: 1.4 $
  + * $Date: 2002/04/21 21:52:32 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -63,7 +63,7 @@
   
   import org.apache.commons.jxpath.ri.Compiler;
   import org.apache.commons.jxpath.ri.compiler.*;
  -import org.apache.commons.jxpath.ri.pointers.*;
  +import org.apache.commons.jxpath.ri.model.*;
   import org.apache.commons.jxpath.ri.EvalContext;
   import java.util.*;
   
  @@ -72,7 +72,7 @@
    * of a union operation like (a | b)
    *
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.3 $ $Date: 2002/04/10 03:40:20 $
  + * @version $Revision: 1.4 $ $Date: 2002/04/21 21:52:32 $
    */
   public class UnionContext extends EvalContext {
       private boolean startedSet = false;
  
  
  
  1.2       +5 -5      jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/compiler/CoreFunction.java
  
  Index: CoreFunction.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/compiler/CoreFunction.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- CoreFunction.java	23 Aug 2001 00:46:59 -0000	1.1
  +++ CoreFunction.java	21 Apr 2002 21:52:32 -0000	1.2
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/compiler/CoreFunction.java,v 1.1 2001/08/23 00:46:59 dmitri Exp $
  - * $Revision: 1.1 $
  - * $Date: 2001/08/23 00:46:59 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/compiler/CoreFunction.java,v 1.2 2002/04/21 21:52:32 dmitri Exp $
  + * $Revision: 1.2 $
  + * $Date: 2002/04/21 21:52:32 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -70,7 +70,7 @@
    * like "position()" or "number()".
    *
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.1 $ $Date: 2001/08/23 00:46:59 $
  + * @version $Revision: 1.2 $ $Date: 2002/04/21 21:52:32 $
    */
   public class CoreFunction extends Operation {
   
  @@ -126,7 +126,7 @@
               case Compiler.FUNCTION_STRING:
               case Compiler.FUNCTION_LANG:
               case Compiler.FUNCTION_NUMBER:
  -                return args.length == 0;
  +                return args == null || args.length == 0;
   
               case Compiler.FUNCTION_COUNT:
               case Compiler.FUNCTION_ID:
  
  
  
  1.3       +6 -4      jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/compiler/CoreOperation.java
  
  Index: CoreOperation.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/compiler/CoreOperation.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- CoreOperation.java	21 Sep 2001 23:22:44 -0000	1.2
  +++ CoreOperation.java	21 Apr 2002 21:52:32 -0000	1.3
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/compiler/CoreOperation.java,v 1.2 2001/09/21 23:22:44 dmitri Exp $
  - * $Revision: 1.2 $
  - * $Date: 2001/09/21 23:22:44 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/compiler/CoreOperation.java,v 1.3 2002/04/21 21:52:32 dmitri Exp $
  + * $Revision: 1.3 $
  + * $Date: 2002/04/21 21:52:32 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -62,6 +62,8 @@
   package org.apache.commons.jxpath.ri.compiler;
   
   import java.util.*;
  +
  +import org.apache.commons.jxpath.ri.*;
   import org.apache.commons.jxpath.ri.Compiler;
   
   /**
  @@ -69,7 +71,7 @@
    * "-", "*" etc.
    *
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.2 $ $Date: 2001/09/21 23:22:44 $
  + * @version $Revision: 1.3 $ $Date: 2002/04/21 21:52:32 $
    */
   public class CoreOperation extends Operation {
   
  
  
  
  1.3       +6 -4      jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/compiler/ExtensionFunction.java
  
  Index: ExtensionFunction.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/compiler/ExtensionFunction.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- ExtensionFunction.java	10 Apr 2002 03:40:20 -0000	1.2
  +++ ExtensionFunction.java	21 Apr 2002 21:52:32 -0000	1.3
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/compiler/ExtensionFunction.java,v 1.2 2002/04/10 03:40:20 dmitri Exp $
  - * $Revision: 1.2 $
  - * $Date: 2002/04/10 03:40:20 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/compiler/ExtensionFunction.java,v 1.3 2002/04/21 21:52:32 dmitri Exp $
  + * $Revision: 1.3 $
  + * $Date: 2002/04/21 21:52:32 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -63,11 +63,13 @@
   
   import java.util.*;
   
  +import org.apache.commons.jxpath.ri.*;
  +
   /**
    * Represents an element of the parse tree representing an extension function call.
    *
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.2 $ $Date: 2002/04/10 03:40:20 $
  + * @version $Revision: 1.3 $ $Date: 2002/04/21 21:52:32 $
    */
   public class ExtensionFunction extends Operation {
   
  
  
  
  1.3       +6 -4      jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/compiler/NodeNameTest.java
  
  Index: NodeNameTest.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/compiler/NodeNameTest.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- NodeNameTest.java	21 Sep 2001 23:22:44 -0000	1.2
  +++ NodeNameTest.java	21 Apr 2002 21:52:32 -0000	1.3
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/compiler/NodeNameTest.java,v 1.2 2001/09/21 23:22:44 dmitri Exp $
  - * $Revision: 1.2 $
  - * $Date: 2001/09/21 23:22:44 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/compiler/NodeNameTest.java,v 1.3 2002/04/21 21:52:32 dmitri Exp $
  + * $Revision: 1.3 $
  + * $Date: 2002/04/21 21:52:32 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -63,9 +63,11 @@
   
   import java.util.*;
   
  +import org.apache.commons.jxpath.ri.*;
  +
   /**
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.2 $ $Date: 2001/09/21 23:22:44 $
  + * @version $Revision: 1.3 $ $Date: 2002/04/21 21:52:32 $
    */
   public class NodeNameTest extends NodeTest {
       private QName qname;
  
  
  
  1.3       +6 -4      jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/compiler/TreeCompiler.java
  
  Index: TreeCompiler.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/compiler/TreeCompiler.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- TreeCompiler.java	21 Sep 2001 23:22:44 -0000	1.2
  +++ TreeCompiler.java	21 Apr 2002 21:52:32 -0000	1.3
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/compiler/TreeCompiler.java,v 1.2 2001/09/21 23:22:44 dmitri Exp $
  - * $Revision: 1.2 $
  - * $Date: 2001/09/21 23:22:44 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/compiler/TreeCompiler.java,v 1.3 2002/04/21 21:52:32 dmitri Exp $
  + * $Revision: 1.3 $
  + * $Date: 2002/04/21 21:52:32 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -62,11 +62,13 @@
   package org.apache.commons.jxpath.ri.compiler;
   
   import java.util.*;
  +
  +import org.apache.commons.jxpath.ri.*;
   import org.apache.commons.jxpath.ri.Compiler;
   
   /**
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.2 $ $Date: 2001/09/21 23:22:44 $
  + * @version $Revision: 1.3 $ $Date: 2002/04/21 21:52:32 $
    */
   public class TreeCompiler implements Compiler {
   
  
  
  
  1.2       +6 -4      jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/compiler/VariableReference.java
  
  Index: VariableReference.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/compiler/VariableReference.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- VariableReference.java	23 Aug 2001 00:46:59 -0000	1.1
  +++ VariableReference.java	21 Apr 2002 21:52:32 -0000	1.2
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/compiler/VariableReference.java,v 1.1 2001/08/23 00:46:59 dmitri Exp $
  - * $Revision: 1.1 $
  - * $Date: 2001/08/23 00:46:59 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/compiler/VariableReference.java,v 1.2 2002/04/21 21:52:32 dmitri Exp $
  + * $Revision: 1.2 $
  + * $Date: 2002/04/21 21:52:32 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -63,11 +63,13 @@
   
   import java.util.*;
   
  +import org.apache.commons.jxpath.ri.*;
  +
   /**
    * An element of the compile tree holding a variable reference.
    *
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.1 $ $Date: 2001/08/23 00:46:59 $
  + * @version $Revision: 1.2 $ $Date: 2002/04/21 21:52:32 $
    */
   public class VariableReference extends Expression {
   
  
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/NodeIterator.java
  
  Index: NodeIterator.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/NodeIterator.java,v 1.1 2002/04/21 21:52:32 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:32 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model;
  
  /**
   * Definition for an iterator for all kinds of Nodes.
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:32 $
   */
  public interface NodeIterator {
  
      int getPosition();
  
      /**
       * Sets the new current position and returns true if there a node
       * at that position.
       */
      boolean setPosition(int position);
  
      NodePointer getNodePointer();
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/NodePointer.java
  
  Index: NodePointer.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/NodePointer.java,v 1.1 2002/04/21 21:52:32 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:32 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model;
  
  import org.apache.commons.jxpath.*;
  import org.apache.commons.jxpath.ri.*;
  import org.apache.commons.jxpath.ri.compiler.*;
  import org.apache.commons.jxpath.ri.Compiler;
  import org.apache.commons.jxpath.ri.model.beans.*;
  import org.apache.commons.jxpath.util.*;
  
  import java.util.*;
  
  /**
   * Common superclass for Pointers of all kinds.  A NodePointer maps to
   * a deterministic XPath that represents the location of a node in an object graph.
   * This XPath uses only simple axes: child, namespace and attribute and only simple,
   * context-independent predicates.
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:32 $
   */
  public abstract class NodePointer implements Pointer, Cloneable {
  
      public static int WHOLE_COLLECTION = Integer.MIN_VALUE;
      protected int index = WHOLE_COLLECTION;
      public static String UNKNOWN_NAMESPACE = "<<unknown namespace>>";
  
      /**
       * Allocates an entirely new NodePointer by iterating through all installed
       * NodePointerFactories until it finds one that can create a pointer.
       */
      public static NodePointer newNodePointer(QName name, Object bean, Locale locale){
          if (bean == null){
              return new NullPointer(name, locale);
          }
          NodePointerFactory[] factories = JXPathContextReferenceImpl.getNodePointerFactories();
          for (int i = 0; i < factories.length; i++){
              NodePointer pointer = factories[i].createNodePointer(name, bean, locale);
              if (pointer != null){
                  return pointer;
              }
          }
          throw new RuntimeException("Could not allocate a NodePointer for object of " + bean.getClass());
      }
  
      /**
       * Allocates an new child NodePointer by iterating through all installed
       * NodePointerFactories until it finds one that can create a pointer.
       */
      public static NodePointer newChildNodePointer(NodePointer parent, QName name, Object bean){
          NodePointerFactory[] factories = JXPathContextReferenceImpl.getNodePointerFactories();
          for (int i = 0; i < factories.length; i++){
              NodePointer pointer = factories[i].createNodePointer(parent, name, bean);
              if (pointer != null){
                  return pointer;
              }
          }
          throw new RuntimeException("Could not allocate a NodePointer for object of " + bean.getClass());
      }
  
      protected NodePointer parent;
      protected Locale locale;
  
      protected NodePointer(NodePointer parent){
          this.parent = parent;
      }
  
      protected NodePointer(NodePointer parent, Locale locale){
          this.parent = parent;
          this.locale = locale;
      }
  
      public NodePointer getParent(){
          return parent;
      }
  
      /**
       * Returns true if this Pointer has no parent.
       */
      public boolean isRoot(){
          return parent == null;
      }
  
      /**
       * If true, this node does not have children
       */
      public boolean isLeaf(){
          Object value = getValue();
          return value == null || JXPathIntrospector.getBeanInfo(value.getClass()).isAtomic();
      }
  
      /**
       * If false, this node is axiliary and can only be used as an intermediate
       * in the chain of pointers.
       */
      public boolean isNode(){
          return true;
      }
  
      /**
       * If the pointer represents a collection, the index identifies
       * an element of that collection.  The default value of <code>index</code>
       * is <code>WHOLE_COLLECTION</code>, which just means that the pointer
       * is not indexed at all.
       * Note: the index on NodePointer starts with 0, not 1.
       */
      public int getIndex(){
          return index;
      }
  
      public void setIndex(int index){
          this.index = index;
      }
  
      /**
       * Returns <code>true</code> if the value of the pointer is an array or
       * a Collection.
       */
      public boolean isCollection(){
          Object value = getBaseValue();
          return value != null && ValueUtils.isCollection(value);
      }
  
      /**
       * If the pointer represents a collection (or collection element),
       * returns the length of the collection. Otherwise returns 1 (even if the value is null).
       */
      public int getLength(){
          Object value = getBaseValue();
          if (value == null){
              return 1;
          }
          return ValueUtils.getLength(value);
      }
  
      /**
       * By default, returns <code>getValue()</code>, can be overridden to
       * return a "canonical" value, like for instance a DOM element should
       * return its string value.
       */
      public Object getCanonicalValue(){
          return getValue();
      }
  
      /**
       * If this pointer manages a transparent container, like a variable,
       * this method returns the pointer to the contents.
       * Only an auxiliary (non-node) pointer can (and should) return a
       * value pointer other than itself.
       */
      public NodePointer getValuePointer(){
          return this;
      }
  
      /**
       * An actual pointer points to an existing part of an object graph, even
       * if it is null. A non-actual pointer represents a part that does not exist
       * at all.
       * For instance consider the pointer "/address/street".
       * If both <em>address</em> and <em>street</em> are not null, the pointer is actual.
       * If <em>address</em> is not null, but <em>street</em> is null, the pointer is still actual.
       * If <em>address</em> is null, the pointer is not actual.
       * (In JavaBeans) if <em>address</em> is not a property of the root bean, a Pointer
       * for this path cannot be obtained at all - actual or otherwise.
       */
      public boolean isActual(){
          if (index == WHOLE_COLLECTION){
              return true;
          }
          else {
              return index >= 0 && index < getLength();
          }
      }
  
      /**
       * Returns the name of this node. Can be null.
       */
      public abstract QName getName();
  
      /**
       * Returns the value represented by the pointer before indexing.
       * So, if the node represents an element of a collection, this
       * method returns the collection itself.
       */
      public abstract Object getBaseValue();
  
      public abstract void setValue(Object value);
  
      /**
       * Checks if this Pointer matches the supplied NodeTest.
       */
      public boolean testNode(NodeTest test){
          if (test == null){
              return true;
          }
          else if (test instanceof NodeNameTest){
              if (!isNode()){
                  return false;
              }
              QName testName = ((NodeNameTest)test).getNodeName();
              QName nodeName = getName();
              String testPrefix = testName.getPrefix();
              String nodePrefix = nodeName.getPrefix();
              if (!equalStrings(testPrefix, nodePrefix)){
                  String testNS = getNamespaceURI(testPrefix);
                  String nodeNS = getNamespaceURI(nodePrefix);
                  if (!equalStrings(testNS, nodeNS)){
                      return false;
                  }
              }
              String testLocalName = testName.getName();
              if (testLocalName.equals("*")){
                  return true;
              }
              return testLocalName.equals(nodeName.getName());
          }
          else if (test instanceof NodeTypeTest){
              if (((NodeTypeTest)test).getNodeType() == Compiler.NODE_TYPE_NODE){
                  return isNode();
              }
          }
          return false;
      }
  
      private static boolean equalStrings(String s1, String s2){
          if (s1 == null && s2 != null){
              return false;
          }
          if (s1 != null && !s1.equals(s2)){
              return false;
          }
          return true;
      }
  
      /**
       *  Called directly by JXPathContext. Must create path and
       *  set value.
       */
      public void createPath(JXPathContext context, Object value){
          setValue(value);
      }
  
      /**
       * Called by a child pointer when it needs to create a parent object.
       * Must create an object described by this pointer and return
       * a new pointer that properly describes the new object.
       */
      public NodePointer createPath(JXPathContext context){
          return this;
      }
  
      /**
       * Called by a child pointer if that child needs to assign the value
       * supplied in the createPath(context, value) call to a non-existent
       * node. This method must may have to expand the collection in order to
       * assign the element.
       */
      public void createChild(JXPathContext context, QName name, int index, Object value){
          throw new RuntimeException("Cannot create an object for path " + asPath() +
                  ", operation is not allowed for this type of node");
      }
  
      /**
       * Called by a child pointer when it needs to create a parent object
       * for a non-existent collection element.  It may have to expand the collection,
       * then create an element object and return a new pointer describing the
       * newly created element.
       */
      public NodePointer createChild(JXPathContext context, QName name, int index){
          throw new RuntimeException("Cannot create an object for path " + asPath() +
                  ", operation is not allowed for this type of node");
      }
  
      /**
       * If the Pointer has a parent, returns the parent's locale;
       * otherwise returns the locale specified when this Pointer
       * was created.
       */
      public Locale getLocale(){
          if (locale == null){
              if (parent != null){
                  locale = parent.getLocale();
              }
          }
          return locale;
      }
  
      /**
       * Returns true if the selected locale name starts
       * with the specified prefix <i>lang</i>, case-insensitive.
       */
      public boolean isLanguage(String lang){
          Locale loc = getLocale();
          String name = loc.toString().replace('_', '-');
          return name.toUpperCase().startsWith(lang.toUpperCase());
      }
  
      /**
       * Returns a NodeIterator that iterates over all children or all children
       * that match the given NodeTest, starting with the specified one.
       */
      public NodeIterator childIterator(NodeTest test, boolean reverse, NodePointer startWith){
          return null;
      }
  
      /**
       * Returns a NodeIterator that iterates over all attributes of the current node
       * matching the supplied node name (could have a wildcard).
       * May return null if the object does not support the attributes.
       */
      public NodeIterator attributeIterator(QName qname){
          return null;
      }
  
      /**
       * Returns a NodeIterator that iterates over all namespaces of the value
       * currently pointed at.
       * May return null if the object does not support the namespaces.
       */
      public NodeIterator namespaceIterator(){
          return null;
      }
  
      /**
       * Returns a NodePointer for the specified namespace. Will return null
       * if namespaces are not supported. Will return UNKNOWN_NAMESPACE if there is no such namespace.
       */
      public NodePointer namespacePointer(String namespace){
          return null;
      }
  
      /**
       * Decodes a namespace prefix to the corresponding URI.
       */
      public String getNamespaceURI(String prefix){
          return null;
      }
  
      /**
       * Returns the namespace URI associated with this Pointer.
       */
      public String getNamespaceURI(){
          return null;
      }
  
      /**
       * Returns true if the supplied prefix represents the
       * default namespace in the context of the current node.
       */
      protected boolean isDefaultNamespace(String prefix){
          if (prefix == null){
              return true;
          }
  
          String namespace = getNamespaceURI(prefix);
          if (namespace == null){
              return false;       // undefined namespace
          }
  
          return namespace.equals(getDefaultNamespaceURI());
      }
  
      protected String getDefaultNamespaceURI(){
          return null;
      }
  
      /**
       * Returns a name that consists of the namespaceURI and the local name
       * of the node.  For non-XML pointers, returns the Pointer's qualified name.
       */
      public QName getExpandedName(){
          return getName();
      }
  
      /**
       * Returns an XPath that maps to this Pointer.
       */
      public String asPath(){
          StringBuffer buffer = new StringBuffer();
          if (getParent() != null){
              buffer.append(getParent().asPath());
              // TBD: the following needs to be redesigned.  What this condition says is
              // "if the parent of this node has already appended this node's name,
              // don't do it again".  However, I would hate to add an ugly API like
              // "isResponsibleForAppendingChildName()".
              if (getParent().isNode() || (parent instanceof NullElementPointer)){
                  QName name = getName();
                  if (name != null){
                      buffer.append('/');
                      buffer.append(name);
                  }
              }
          }
          else {
              QName name = getName();
              buffer.append(name);
          }
          if (index != WHOLE_COLLECTION && isCollection()){
              buffer.append('[').append(index + 1).append(']');
          }
          return buffer.toString();
      }
  
      public Object clone(){
          try {
              return super.clone();
          }
          catch (CloneNotSupportedException ex){
              // Of course it is supported
              ex.printStackTrace();
          }
          return null;
      }
  
      public String toString(){
          return asPath();
      }
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/NodePointerFactory.java
  
  Index: NodePointerFactory.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/NodePointerFactory.java,v 1.1 2002/04/21 21:52:32 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:32 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model;
  
  import org.apache.commons.jxpath.ri.QName;
  
  import java.util.*;
  
  /**
   * Creates NodePointers for objects of a certain type.
   * NodePointerFactories are ordered according to the values returned
   * by the "getOrder" method and always queried in that order.
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:32 $
   */
  public interface NodePointerFactory {
  
      /**
       * The factory name determines its position between other factories.
       */
      public int getOrder();
  
      /**
       * Create a NodePointer for the supplied object.  The node will represent
       * the "root" object a path.
       *
       * Return null if this factory does not recognize objects of the supplied type.
       */
      public NodePointer createNodePointer(QName name, Object object, Locale locale);
  
      /**
       * Create a NodePointer for the supplied child object.
       * <p>
       * Return null if this factory does not recognize objects of the supplied type.
       */
      public NodePointer createNodePointer(NodePointer parent, QName name, Object object);
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/VariablePointer.java
  
  Index: VariablePointer.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/VariablePointer.java,v 1.1 2002/04/21 21:52:32 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:32 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model;
  
  import org.apache.commons.jxpath.*;
  import org.apache.commons.jxpath.ri.*;
  import org.apache.commons.jxpath.ri.compiler.*;
  import org.apache.commons.jxpath.ri.model.beans.*;
  import org.apache.commons.jxpath.util.*;
  
  import java.util.*;
  
  /**
   * Pointer to a context variable.
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:32 $
   */
  public class VariablePointer extends NodePointer {
      private Variables variables;
      private QName name;
      private NodePointer valuePointer;
      private boolean actual;
  
      public VariablePointer(Variables variables, QName name){
          super(null);
          this.variables = variables;
          this.name = name;
          actual = true;
      }
  
      public VariablePointer(QName name){
          super(null);
          this.name = name;
          actual = false;
      }
  
      public boolean isNode(){
          return false;
      }
  
      public QName getName(){
          return name;
      }
  
      public Object getBaseValue(){
          if (!actual){
              throw new RuntimeException("Undefined variable: " + name);
          }
          return variables.getVariable(name.getName());
      }
  
      public Object getValue(){
          Object value = getBaseValue();
          if (index != WHOLE_COLLECTION){
              return ValueUtils.getValue(value, index);
          }
          return value;
      }
  
      public void setValue(Object value){
          if (!actual){
              throw new RuntimeException("Cannot set undefined variable: " + name);
          }
          valuePointer = null;
          if (index != WHOLE_COLLECTION){
              Object collection = getBaseValue();
              ValueUtils.setValue(collection, index, value);
          }
          else {
              variables.declareVariable(name.getName(), value);
          }
      }
  
      public boolean isActual(){
          return actual;
      }
  
      public NodePointer getValuePointer(){
          if (valuePointer == null){
              Object value = null;
              if (actual){
                  value = getValue();
              }
              valuePointer = NodePointer.newChildNodePointer(this, null, value);
          }
          return valuePointer;
      }
  
      public int getLength(){
          if (actual){
              return super.getLength();
          }
          return 0;
      }
  
      public void createPath(JXPathContext context, Object value){
          if (actual){
              setValue(value);
              return;
          }
          createPath(context).setValue(value);
      }
  
      public NodePointer createPath(JXPathContext context){
          if (!actual){
              AbstractFactory factory = getAbstractFactory(context);
              if (!factory.declareVariable(context, name.toString())){
                  throw new RuntimeException("Factory cannot define variable '" + name + "' for path: " + asPath());
              }
              findVariables(context);
              // Assert: actual == true
          }
          return this;
      }
  
      public NodePointer createChild(JXPathContext context, QName name, int index){
          Object collection = createCollection(context, index);
          if (!isActual() || (index != 0 && index != WHOLE_COLLECTION)){
              AbstractFactory factory = getAbstractFactory(context);
              // Ignore the name passed as a parameter, pass the name of the variable instead
              if (!factory.createObject(context, this, collection, getName().toString(), index)){
                  throw new RuntimeException("Factory could not create object path: " + asPath());
              }
              setIndex(index);
          }
          return this;
      }
  
      /**
       */
      public void createChild(JXPathContext context, QName name, int index, Object value){
          Object collection = createCollection(context, index);
          ValueUtils.setValue(collection, index, value);
      }
  
      private Object createCollection(JXPathContext context, int index){
          createPath(context);
  
          Object collection = getBaseValue();
          if (collection == null){
              throw new RuntimeException("Factory did not assign a collection to variable '" + name + "' for path: " + asPath());
          }
  
          if (index == WHOLE_COLLECTION){
              index = 0;
          }
          else if (index < 0){
              throw new RuntimeException("Index is less than 1: " + asPath());
          }
  
          if (index >= getLength()){
              collection = ValueUtils.expandCollection(collection, index + 1);
              variables.declareVariable(name.toString(), collection);
          }
  
          return collection;
      }
  
      protected void findVariables(JXPathContext context){
          valuePointer = null;
          JXPathContext varCtx = context;
          while (varCtx != null){
              variables = varCtx.getVariables();
              if (variables.isDeclaredVariable(name.toString())){
                  actual = true;
                  break;
              }
              varCtx = varCtx.getParentContext();
              variables = null;
          }
      }
  
      public int hashCode(){
          return (actual ? System.identityHashCode(variables): 0) + name.hashCode() + index;
      }
  
      public boolean equals(Object object){
          if (object == this){
              return true;
          }
  
          if (!(object instanceof VariablePointer)){
              return false;
          }
  
          VariablePointer other = (VariablePointer)object;
          return variables == other.variables &&
                  name.equals(other.name) &&
                  index == other.index;
      }
  
      public String asPath(){
          StringBuffer buffer = new StringBuffer();
          buffer.append('$');
          buffer.append(name);
          if (!actual){
              if (index != WHOLE_COLLECTION){
                  buffer.append('[').append(index + 1).append(']');
              }
          }
          else if (index != WHOLE_COLLECTION && (getValue() == null || isCollection())){
              buffer.append('[').append(index + 1).append(']');
          }
          return buffer.toString();
      }
  
      public NodeIterator childIterator(NodeTest test, boolean reverse, NodePointer startWith){
          return getValuePointer().childIterator(test, reverse, startWith);
      }
  
      public NodeIterator attributeIterator(QName name){
          return getValuePointer().attributeIterator(name);
      }
  
      public NodeIterator namespaceIterator(){
          return getValuePointer().namespaceIterator();
      }
  
      public NodePointer namespacePointer(String name){
          return getValuePointer().namespacePointer(name);
      }
  
      public boolean testNode(NodeTest nodeTest){
          return getValuePointer().testNode(nodeTest);
      }
  
      private AbstractFactory getAbstractFactory(JXPathContext context){
          AbstractFactory factory = context.getFactory();
          if (factory == null){
              throw new RuntimeException("Factory is not set on the JXPathContext - cannot create path: " + asPath());
          }
          return factory;
      }
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/package.html
  
  Index: package.html
  ===================================================================
  <body>
  The "model" package defines APIs that are implemented 
  for every object model to be supported by JXPath. 
  The main part of this API is Pointers, which are a mechanism 
  for identifying locations of objects within an object graph.
  </body>
  
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/BeanAttributeIterator.java
  
  Index: BeanAttributeIterator.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/BeanAttributeIterator.java,v 1.1 2002/04/21 21:52:33 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:33 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model.beans;
  
  import org.apache.commons.jxpath.*;
  import org.apache.commons.jxpath.ri.*;
  import org.apache.commons.jxpath.ri.Compiler;
  import org.apache.commons.jxpath.ri.compiler.*;
  import org.apache.commons.jxpath.ri.model.NodeIterator;
  import org.apache.commons.jxpath.ri.model.NodePointer;
  
  import java.lang.reflect.*;
  import java.util.*;
  import java.beans.*;
  
  /**
   * An iterator of attributes of a JavaBean. Currently supports only one
   * attribute - "lang".
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:33 $
   */
  public class BeanAttributeIterator implements NodeIterator {
      private NodePointer parent;
      private QName name;
      private int position = 0;
  
      public BeanAttributeIterator(NodePointer parent, QName name){
          this.parent = parent;
          this.name = name;
      }
  
      public NodePointer getNodePointer(){
          return new LangAttributePointer(parent);
      }
  
      public int getPosition(){
          return position;
      }
  
      public boolean setPosition(int position){
          this.position = position;
          return position == 1 && name.getPrefix() != null && name.getPrefix().equals("xml") &&
              (name.getName().equals("lang") || name.getName().equals("*"));
      }
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/BeanPointer.java
  
  Index: BeanPointer.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/BeanPointer.java,v 1.1 2002/04/21 21:52:33 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:33 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model.beans;
  
  import org.apache.commons.jxpath.*;
  import org.apache.commons.jxpath.ri.*;
  import org.apache.commons.jxpath.ri.Compiler;
  import org.apache.commons.jxpath.ri.compiler.*;
  import org.apache.commons.jxpath.ri.model.*;
  import org.apache.commons.jxpath.ri.model.NodePointer;
  import org.apache.commons.jxpath.util.*;
  
  import java.lang.reflect.*;
  import java.util.*;
  import java.beans.*;
  
  /**
   * A Pointer that points to a JavaBean or a collection. It is the first element of
   * a path, following elements will by of type PropertyPointer.
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:33 $
   */
  public class BeanPointer extends PropertyOwnerPointer {
      private QName name;
      private Object bean;
      private JXPathBeanInfo beanInfo;
      private PropertyDescriptor propertyDescriptors[];
      private String[] names;
  
      public BeanPointer(QName name, Object bean, JXPathBeanInfo beanInfo, Locale locale){
          super(null, locale);
          this.name = name;
          this.bean = bean;
          this.beanInfo = beanInfo;
      }
  
      /**
       * @param name is the name given to the first node
       */
      public BeanPointer(NodePointer parent, QName name, Object bean, JXPathBeanInfo beanInfo){
          super(parent);
          this.name = name;
          this.bean = bean;
          this.beanInfo = beanInfo;
      }
  
      public PropertyPointer getPropertyPointer(){
          return new BeanPropertyPointer(this, beanInfo);
      }
  
      public QName getName(){
          return name;
      }
  
      /**
       * Returns the bean itself
       */
      public Object getBaseValue(){
          return bean;
      }
  
      /**
       * Throws an exception if you try to change the root element.
       */
      public void setValue(Object value){
          if (parent instanceof PropertyPointer){
              parent.setValue(value);
          }
          else {
              throw new UnsupportedOperationException("Cannot setValue of an object that is not some other object's property");
          }
      }
  
      /**
       * If the bean is a collection, returns the length of that collection,
       * otherwise returns 1.
       */
      public int getLength(){
          return ValueUtils.getLength(getBaseValue());
      }
  
      public int hashCode(){
          return name == null ? 0 : name.hashCode();
      }
  
      public boolean equals(Object object){
          if (object == this){
              return true;
          }
  
          if (!(object instanceof BeanPointer)){
              return false;
          }
  
          BeanPointer other = (BeanPointer)object;
          if ((name == null && other.name != null) ||
                  (name != null && !name.equals(other.name))){
              return false;
          }
  
          if (bean instanceof Number || bean instanceof String || bean instanceof Boolean){
              return bean.equals(other.bean);
          }
          return bean == other.bean;
      }
  
      /**
       * Empty string
       */
      public String asPath(){
          if (parent != null){
              return super.asPath();
          }
          else if (bean == null){
              return "null()";
          }
          else if (bean instanceof Number){
              String string = bean.toString();
              if (string.endsWith(".0")){
                  string = string.substring(0, string.length() - 2);
              }
              return string;
          }
          else if (bean instanceof Boolean){
              return ((Boolean)bean).booleanValue() ? "true()" : "false()";
          }
          else if (bean instanceof String){
              return "'" + bean + "'";
          }
          return "";
      }
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/BeanPointerFactory.java
  
  Index: BeanPointerFactory.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/BeanPointerFactory.java,v 1.1 2002/04/21 21:52:33 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:33 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model.beans;
  
  import org.apache.commons.jxpath.*;
  import org.apache.commons.jxpath.ri.QName;
  import org.apache.commons.jxpath.ri.model.NodePointer;
  import org.apache.commons.jxpath.ri.model.NodePointerFactory;
  
  import java.util.*;
  
  /**
   * Implements NodePointerFactory for JavaBeans.
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:33 $
   */
  public class BeanPointerFactory implements NodePointerFactory {
  
      public static final int BEAN_POINTER_FACTORY_ORDER = 900;
  
      public int getOrder(){
          return BEAN_POINTER_FACTORY_ORDER;
      }
  
      public NodePointer createNodePointer(QName name, Object bean, Locale locale){
          JXPathBeanInfo bi = JXPathIntrospector.getBeanInfo(bean.getClass());
          return new BeanPointer(name, bean, bi, locale);
      }
  
      public NodePointer createNodePointer(NodePointer parent, QName name, Object bean){
          parent = (NodePointer)parent.clone();
          if (bean == null){
              return new NullPointer(parent, name);
          }
  
          JXPathBeanInfo bi = JXPathIntrospector.getBeanInfo(bean.getClass());
          return new BeanPointer(parent, name, bean, bi);
      }
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/BeanPropertyPointer.java
  
  Index: BeanPropertyPointer.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/BeanPropertyPointer.java,v 1.1 2002/04/21 21:52:33 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:33 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model.beans;
  
  import org.apache.commons.jxpath.*;
  import org.apache.commons.jxpath.ri.QName;
  import org.apache.commons.jxpath.ri.model.*;
  import org.apache.commons.jxpath.util.*;
  
  import java.util.*;
  import java.beans.*;
  
  /**
   * Pointer pointing to a property of a JavaBean.
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:33 $
   */
  public class BeanPropertyPointer extends PropertyPointer {
      private String propertyName;
      private JXPathBeanInfo beanInfo;
      private PropertyDescriptor propertyDescriptors[];
      private PropertyDescriptor propertyDescriptor;
      private String[] names;
      private static final Object UNINITIALIZED = new Object();
      private Object baseValue = UNINITIALIZED;
      private Object value = UNINITIALIZED;
  
      public BeanPropertyPointer(NodePointer parent, JXPathBeanInfo beanInfo){
          super(parent);
          this.beanInfo = beanInfo;
      }
  
      /**
       * This type of node is auxiliary.
       */
      public boolean isNode(){
          return false;
      }
  
      /**
       * Number of the bean's properties.
       */
      public int getPropertyCount(){
          return getPropertyDescriptors().length;
      }
  
      /**
       * Names of all properties, sorted alphabetically
       */
      public String[] getPropertyNames(){
          if (names == null){
              PropertyDescriptor pds[] = getPropertyDescriptors();
              names = new String[pds.length];
              for (int i = 0; i < names.length; i++){
                  names[i] = pds[i].getName();
              }
          }
          return names;
      }
  
      /**
       * Select a property by name
       */
      public void setPropertyName(String propertyName){
          setPropertyIndex(UNSPECIFIED_PROPERTY);
          this.propertyName = propertyName;
      }
  
      /**
       * Selects a property by its offset in the alphabetically sorted list.
       */
      public void setPropertyIndex(int index){
          if (propertyIndex != index){
              super.setPropertyIndex(index);
              propertyName = null;
              propertyDescriptor = null;
              baseValue = UNINITIALIZED;
              value = UNINITIALIZED;
          }
      }
  
      /**
       * If the property contains a collection, then the length of that
       * collection, otherwise - 1.
       */
      public int getLength(){
          return ValueUtils.getLength(getBaseValue());
      }
  
      /**
       * The value of the currently selected property.
       */
      public Object getBaseValue(){
          if (baseValue == UNINITIALIZED){
              PropertyDescriptor pd = getPropertyDescriptor();
              if (pd == null){
                  return null;
              }
              baseValue = ValueUtils.getValue(getBean(), pd);
          }
          return baseValue;
      }
  
      public void setIndex(int index){
          if (this.index != index){
              super.setIndex(index);
              value = UNINITIALIZED;
          }
      }
  
      /**
       * If index == WHOLE_COLLECTION, the value of the property, otherwise
       * the value of the index'th element of the collection represented by the
       * property. If the property is not a collection, index should be zero
       * and the value will be the property itself.
       */
      public Object getValue(){
          if (value == UNINITIALIZED){
              PropertyDescriptor pd = getPropertyDescriptor();
              if (pd == null){
                  value = null;
              }
              else {
                  if (index == WHOLE_COLLECTION){
                      value = ValueUtils.getValue(getBean(), pd);
                  }
                  else {
                      value = ValueUtils.getValue(getBean(), pd, index);
                  }
              }
          }
          return value;
      }
  
      protected boolean isActualProperty(){
          return getPropertyDescriptor() != null;
      }
  
      /**
       * If index == WHOLE_COLLECTION, change the value of the property, otherwise
       * change the value of the index'th element of the collection
       * represented by the property.
       */
      public void setValue(Object value){
          PropertyDescriptor pd = getPropertyDescriptor();
          if (pd == null){
              throw new RuntimeException("Cannot set property: " + asPath() + " - no such property");
          }
  
          if (index == WHOLE_COLLECTION){
              ValueUtils.setValue(getBean(), pd, value);
          }
          else {
              ValueUtils.setValue(getBean(), pd, index, value);
          }
          this.value = value;
      }
  
      public NodePointer createPath(JXPathContext context){
          if (getValue() == null){
              AbstractFactory factory = getAbstractFactory(context);
              int inx = (index == WHOLE_COLLECTION ? 0 : index);
              if (!factory.createObject(context, this, getBean(), getPropertyName(), inx)){
                  throw new RuntimeException("Factory could not create an object for path: " + asPath());
              }
              baseValue = UNINITIALIZED;
              value = UNINITIALIZED;
          }
          return this;
      }
  
      public NodePointer createChild(JXPathContext context, QName name, int index){
          return createPath(context).getValuePointer().createChild(context, name, index);
  //        NodePointer pointer = setIndexExpandingCollection(context, name, index);
  //        return pointer.createPath(context);
      }
  
      public void createChild(JXPathContext context, QName name, int index, Object value){
          createPath(context).getValuePointer().createChild(context, name, index, value);
  //        NodePointer pointer = setIndexExpandingCollection(context, name, index);
  //        pointer.createPath(context, value);
      }
  
      private BeanPropertyPointer setIndexExpandingCollection(JXPathContext context, QName name, int index){
          // Ignore the name passed to us, use our own information
          PropertyDescriptor pd = getPropertyDescriptor();
          if (pd == null){
              throw new RuntimeException("Cannot create path: " + asPath() +
                      " - property '" + getPropertyName() + "' does not exist");
          }
  
          if (index < 0){
              throw new RuntimeException("Index is less than 1: " + asPath());
          }
  
          if (index >= getLength()){
              AbstractFactory factory = getAbstractFactory(context);
              if (!factory.createObject(context, this, getBean(), getPropertyName(), index)){
                  throw new RuntimeException("Factory could not create path " + asPath());
              }
          }
          BeanPropertyPointer clone = (BeanPropertyPointer)this.clone();
          clone.baseValue = UNINITIALIZED;
          clone.value = UNINITIALIZED;
          clone.setIndex(index);
          return clone;
      }
  
      /**
       * Name of the currently selected property.
       */
      public String getPropertyName(){
          if (propertyName == null){
              PropertyDescriptor pd = getPropertyDescriptor();
              if (pd != null){
                  propertyName = pd.getName();
              }
          }
          return propertyName != null ? propertyName : "*";
      }
  
      /**
       * Finds the property descriptor corresponding to the current property index.
       */
      private PropertyDescriptor getPropertyDescriptor(){
          if (propertyDescriptor == null){
              int inx = getPropertyIndex();
              if (inx == UNSPECIFIED_PROPERTY){
                  propertyDescriptor = beanInfo.getPropertyDescriptor(propertyName);
              }
              else {
                  PropertyDescriptor propertyDescriptors[] = getPropertyDescriptors();
                  if (inx >=0 && inx < propertyDescriptors.length){
                      propertyDescriptor = propertyDescriptors[inx];
                  }
                  else {
                      propertyDescriptor = null;
                  }
              }
          }
          return propertyDescriptor;
      }
  
      protected PropertyDescriptor[] getPropertyDescriptors(){
          if (propertyDescriptors == null){
              propertyDescriptors = beanInfo.getPropertyDescriptors();
          }
          return propertyDescriptors;
      }
  
      private AbstractFactory getAbstractFactory(JXPathContext context){
          AbstractFactory factory = context.getFactory();
          if (factory == null){
              throw new RuntimeException("Factory is not set on the JXPathContext - cannot create path: " + asPath());
          }
          return factory;
      }
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/CollectionPointer.java
  
  Index: CollectionPointer.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/CollectionPointer.java,v 1.1 2002/04/21 21:52:33 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:33 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model.beans;
  
  import org.apache.commons.jxpath.*;
  import org.apache.commons.jxpath.ri.*;
  import org.apache.commons.jxpath.ri.compiler.*;
  import org.apache.commons.jxpath.ri.model.*;
  import org.apache.commons.jxpath.ri.model.NodeIterator;
  import org.apache.commons.jxpath.ri.model.NodePointer;
  import org.apache.commons.jxpath.util.*;
  
  import java.util.*;
  
  /**
   * Transparent pointer to a collection (array or Collection).
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:33 $
   */
  public class CollectionPointer extends NodePointer {
      private Object collection;
      private NodePointer valuePointer;
  
      public CollectionPointer(Object collection, Locale locale){
          super(null, locale);
          this.collection = collection;
      }
  
      public CollectionPointer(NodePointer parent, Object collection){
          super(parent);
          this.collection = collection;
      }
  
      public QName getName(){
          return null;
      }
  
      public Object getBaseValue(){
          return collection;
      }
  
      public Object getValue(){
          if (index != WHOLE_COLLECTION){
              return ValueUtils.getValue(collection, index);
          }
          return collection;
      }
  
      public void setValue(Object value){
          if (index == WHOLE_COLLECTION){
              parent.setValue(value);
          }
          else {
              ValueUtils.setValue(collection, index, value);
          }
      }
  
      public NodePointer getValuePointer(){
          if (valuePointer == null){
              Object value = getValue();
              valuePointer = NodePointer.newChildNodePointer(this, getName(), value);
          }
          return valuePointer;
      }
  
      public void createChild(JXPathContext context, QName name, int index, Object value){
          if (parent instanceof PropertyPointer){
              parent.createChild(context, name, index, value);
          }
          else {
              Object collection = getBaseValue();
              if (ValueUtils.getLength(collection) <= index){
                  ValueUtils.expandCollection(getValue(), index + 1);
              }
              ValueUtils.setValue(collection, index, value);
          }
      }
  
      public NodePointer createPath(JXPathContext context){
          if (parent instanceof PropertyPointer){
              return parent.createPath(context);
          }
          else {
              Object collection = getBaseValue();
              if (ValueUtils.getLength(collection) <= index){
                  ValueUtils.expandCollection(getValue(), index + 1);
              }
              return this;
          }
      }
  
      public NodePointer createChild(JXPathContext context, QName name, int index){
          if (parent instanceof PropertyPointer){
              return parent.createChild(context, name, index);
          }
          else {
              Object collection = getBaseValue();
              if (ValueUtils.getLength(collection) <= index){
                  ValueUtils.expandCollection(getValue(), index + 1);
              }
              return this;
          }
      }
  
      public int hashCode(){
          return System.identityHashCode(collection) + index;
      }
  
      public boolean equals(Object object){
          if (object == this){
              return true;
          }
  
          if (!(object instanceof CollectionPointer)){
              return false;
          }
  
          CollectionPointer other = (CollectionPointer)object;
          return collection == other.collection &&
                  index == other.index;
      }
  
      public NodeIterator childIterator(NodeTest test, boolean reverse, NodePointer startWith){
          if (index == WHOLE_COLLECTION){
              return null;
          }
          return getValuePointer().childIterator(test, reverse, startWith);
      }
  
      public NodeIterator attributeIterator(QName name){
          return getValuePointer().attributeIterator(name);
      }
  
      public NodeIterator namespaceIterator(){
          return getValuePointer().namespaceIterator();
      }
  
      public NodePointer namespacePointer(String namespace){
          return getValuePointer().namespacePointer(namespace);
      }
  
      public boolean testNode(NodeTest nodeTest){
          return getValuePointer().testNode(nodeTest);
      }
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/CollectionPointerFactory.java
  
  Index: CollectionPointerFactory.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/CollectionPointerFactory.java,v 1.1 2002/04/21 21:52:33 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:33 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model.beans;
  
  import org.apache.commons.jxpath.Container;
  import org.apache.commons.jxpath.ri.QName;
  import org.apache.commons.jxpath.ri.model.*;
  import org.apache.commons.jxpath.ri.model.NodePointer;
  import org.apache.commons.jxpath.ri.model.NodePointerFactory;
  import org.apache.commons.jxpath.util.*;
  
  import java.util.*;
  
  /**
   * Implements NodePointerFactory for stand-alone collections.
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:33 $
   */
  public class CollectionPointerFactory implements NodePointerFactory {
  
      public static final int COLLECTION_POINTER_FACTORY_ORDER = 10;
  
      public int getOrder(){
          return COLLECTION_POINTER_FACTORY_ORDER;
      }
  
      public NodePointer createNodePointer(QName name, Object bean, Locale locale){
          if (ValueUtils.isCollection(bean)){
              return new CollectionPointer(bean, locale);
          }
          return null;
      }
  
      public NodePointer createNodePointer(NodePointer parent, QName name, Object bean){
          if (ValueUtils.isCollection(bean)){
              return new CollectionPointer(parent, bean);
          }
          return null;
      }
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/DynamicPointer.java
  
  Index: DynamicPointer.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/DynamicPointer.java,v 1.1 2002/04/21 21:52:33 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:33 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model.beans;
  
  import org.apache.commons.jxpath.*;
  import org.apache.commons.jxpath.ri.*;
  import org.apache.commons.jxpath.ri.Compiler;
  import org.apache.commons.jxpath.ri.compiler.*;
  import org.apache.commons.jxpath.ri.model.*;
  import org.apache.commons.jxpath.ri.model.NodePointer;
  import org.apache.commons.jxpath.util.*;
  
  import java.lang.reflect.*;
  import java.util.*;
  import java.beans.*;
  
  /**
   * A Pointer that points to an object with Dynamic Properties. It is used
   * for the first element of a path; following elements will by of type PropertyPointer.
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:33 $
   */
  public class DynamicPointer extends PropertyOwnerPointer {
      private QName name;
      private Object bean;
      private DynamicPropertyHandler handler;
      private String[] names;
  
      public DynamicPointer(QName name, Object bean, DynamicPropertyHandler handler, Locale locale){
          super(null, locale);
          this.name = name;
          this.bean = bean;
          this.handler = handler;
      }
  
      public DynamicPointer(NodePointer parent, QName name, Object bean, DynamicPropertyHandler handler){
          super(parent);
          this.name = name;
          this.bean = bean;
          this.handler = handler;
      }
  
      public PropertyPointer getPropertyPointer(){
          return new DynamicPropertyPointer(this, handler);
      }
  
      public QName getName(){
          return name;
      }
  
      /**
       * Returns the DP object iself.
       */
      public Object getBaseValue(){
          return bean;
      }
  
      /**
       * Throws UnsupportedOperationException.
       */
      public void setValue(Object value){
          throw new UnsupportedOperationException("Cannot replace the root object");
      }
  
      /**
       * If the bean is a collection, returns the length of that collection,
       * otherwise returns 1.
       */
      public int getLength(){
          return ValueUtils.getLength(getBaseValue());
      }
  
      /**
       * Empty string
       */
      public String asPath(){
          if (parent != null){
              return super.asPath();
          }
          return "";
      }
  
      public int hashCode(){
          return System.identityHashCode(bean) + name.hashCode();
      }
  
      public boolean equals(Object object){
          if (object == this){
              return true;
          }
  
          if (!(object instanceof DynamicPointer)){
              return false;
          }
  
          DynamicPointer other = (DynamicPointer)object;
          return bean == other.bean && name.equals(other.name);
      }
  
      public String toString(){
          return bean.getClass().getName() + "@" + System.identityHashCode(bean) +
              "(" + name + ")";
      }
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/DynamicPointerFactory.java
  
  Index: DynamicPointerFactory.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/DynamicPointerFactory.java,v 1.1 2002/04/21 21:52:33 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:33 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model.beans;
  
  import org.apache.commons.jxpath.*;
  import org.apache.commons.jxpath.ri.QName;
  import org.apache.commons.jxpath.ri.model.*;
  import org.apache.commons.jxpath.ri.model.NodePointer;
  import org.apache.commons.jxpath.ri.model.NodePointerFactory;
  import org.apache.commons.jxpath.util.*;
  
  import java.util.*;
  
  /**
   * Implements NodePointerFactory for Dynamic classes like Map.
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:33 $
   */
  public class DynamicPointerFactory implements NodePointerFactory {
  
      public static final int DYNAMIC_POINTER_FACTORY_ORDER = 800;
  
      public int getOrder(){
          return DYNAMIC_POINTER_FACTORY_ORDER;
      }
  
      public NodePointer createNodePointer(QName name, Object bean, Locale locale){
          JXPathBeanInfo bi = JXPathIntrospector.getBeanInfo(bean.getClass());
          if (bi.isDynamic()){
              DynamicPropertyHandler handler = ValueUtils.getDynamicPropertyHandler(bi.getDynamicPropertyHandlerClass());
              return new DynamicPointer(name, bean, handler, locale);
          }
          return null;
      }
  
      public NodePointer createNodePointer(NodePointer parent, QName name, Object bean){
  //        if (bean == null){
  //            return new NullPropertyPointer(parent);
  //        }
  //
  //        JXPathBeanInfo bi = JXPathIntrospector.getBeanInfo(bean.getClass());
  //        if (bi.isDynamic()){
  //            DynamicPropertyHandler handler = ValueUtils.getDynamicPropertyHandler(bi.getDynamicPropertyHandlerClass());
  //            return new DynamicPropertyPointer(parent, handler);
  //        }
  //        parent = (NodePointer)parent.clone();
          if (bean == null){
              return new NullPointer(parent, name);
          }
  
          JXPathBeanInfo bi = JXPathIntrospector.getBeanInfo(bean.getClass());
          if (bi.isDynamic()){
              DynamicPropertyHandler handler = ValueUtils.getDynamicPropertyHandler(bi.getDynamicPropertyHandlerClass());
              return new DynamicPointer(parent, name, bean, handler);
          }
          return null;
      }
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/DynamicPropertyPointer.java
  
  Index: DynamicPropertyPointer.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/DynamicPropertyPointer.java,v 1.1 2002/04/21 21:52:33 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:33 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model.beans;
  
  import org.apache.commons.jxpath.*;
  import org.apache.commons.jxpath.ri.QName;
  import org.apache.commons.jxpath.ri.model.*;
  import org.apache.commons.jxpath.util.*;
  
  import java.util.*;
  import java.beans.*;
  
  /**
   * Pointer pointing to a property of an object with dynamic properties.
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:33 $
   */
  public class DynamicPropertyPointer extends PropertyPointer {
      private DynamicPropertyHandler handler;
      private String name;
      private String[] names;
      private String requiredPropertyName;
  
      public DynamicPropertyPointer(NodePointer parent, DynamicPropertyHandler handler){
          super(parent);
          this.handler = handler;
      }
  
      /**
       * This type of node is auxiliary.
       */
      public boolean isNode(){
          return false;
      }
  
      /**
       * Number of the DP object's properties.
       */
      public int getPropertyCount(){
          return getPropertyNames().length;
      }
  
      /**
       * Names of all properties, sorted alphabetically
       */
      public String[] getPropertyNames(){
          if (names == null){
              String allNames[] = handler.getPropertyNames(getBean());
              names = new String[allNames.length];
              for (int i = 0; i < names.length; i++){
                  names[i] = allNames[i];
              }
              Arrays.sort(names);
              if (requiredPropertyName != null){
                  int inx = Arrays.binarySearch(names, requiredPropertyName);
                  if (inx < 0){
                      allNames = names;
                      names = new String[allNames.length + 1];
                      names[0] = requiredPropertyName;
                      System.arraycopy(allNames, 0, names, 1, allNames.length);
                      Arrays.sort(names);
                  }
              }
          }
          return names;
      }
  
      /**
       * Returns the name of the currently selected property or "*"
       * if none has been selected.
       */
      public String getPropertyName(){
          if (name == null){
              String names[] = getPropertyNames();
              if (propertyIndex >=0 && propertyIndex < names.length){
                  name = names[propertyIndex];
              }
              else {
                  name = "*";
              }
          }
          return name;
      }
  
      /**
       * Select a property by name.  If the supplied name is
       * not one of the object's existing properties, it implicitly
       * adds this name to the object's property name list. It does not
       * set the property value though. In order to set the property
       * value, call setValue().
       */
      public void setPropertyName(String propertyName){
          setPropertyIndex(UNSPECIFIED_PROPERTY);
          this.name = propertyName;
          requiredPropertyName = propertyName;
          if (names != null && Arrays.binarySearch(names, propertyName) < 0){
              names = null;
          }
      }
  
      /**
       * Index of the currently selected property in the list of all
       * properties sorted alphabetically.
       */
      public int getPropertyIndex(){
          if (propertyIndex == UNSPECIFIED_PROPERTY){
              String names[] = getPropertyNames();
              for (int i = 0; i < names.length; i++){
                  if (names[i].equals(name)){
                      setPropertyIndex(i);
                      break;
                  }
              }
          }
          return super.getPropertyIndex();
      }
  
      /**
       * Index a property by its index in the list of all
       * properties sorted alphabetically.
       */
      public void setPropertyIndex(int index){
          if (propertyIndex != index){
              super.setPropertyIndex(index);
              name = null;
          }
      }
  
      /**
       * If the property contains a collection, then the length of that
       * collection, otherwise - 1.
       */
      public int getLength(){
          return ValueUtils.getLength(getValue());
      }
  
      /**
       * Returns the value of the property, not an element of the collection
       * represented by the property, if any.
       */
      public Object getBaseValue(){
          return handler.getProperty(getBean(), getPropertyName());
      }
  
      /**
       * If index == WHOLE_COLLECTION, the value of the property, otherwise
       * the value of the index'th element of the collection represented by the
       * property. If the property is not a collection, index should be zero
       * and the value will be the property itself.
       */
      public Object getValue(){
          Object value;
          if (index == WHOLE_COLLECTION){
              value = handler.getProperty(getBean(), getPropertyName());
          }
          else {
              value = ValueUtils.getValue(handler.getProperty(getBean(), getPropertyName()), index);
          }
          return value;
      }
  
      /**
       * A dynamic property is always considered actual - all keys are apparently
       * existing with possibly the value of null.
       */
      protected boolean isActualProperty(){
          return true;
      }
  
      /**
       * If index == WHOLE_COLLECTION, change the value of the property, otherwise
       * change the value of the index'th element of the collection
       * represented by the property.
       */
      public void setValue(Object value){
          if (index == WHOLE_COLLECTION){
              handler.setProperty(getBean(), getPropertyName(), value);
          }
          else {
              ValueUtils.setValue(handler.getProperty(getBean(), getPropertyName()), index, value);
          }
      }
  
      public void createPath(JXPathContext context, Object value){
          createChild(context, getName(), index, value);
      }
  
      public void createChild(JXPathContext context, QName name, int index, Object value){
          // Ignore the name passed to us, use our own data
          if (index == WHOLE_COLLECTION){
              handler.setProperty(getBean(), getPropertyName(), value);
          }
          else {
              Object collection = getBaseValue();
              if (collection == null){
                  AbstractFactory factory = getAbstractFactory(context);
                  if (!factory.createObject(context, this, getBean(), getPropertyName(), 0)){
                      throw new RuntimeException("Factory could not create an object for path: " + asPath());
                  }
                  collection = getBaseValue();
              }
  
              if (index < 0){
                  throw new RuntimeException("Index is less than 1: " + asPath());
              }
  
              if (index >= getLength()){
                  collection = ValueUtils.expandCollection(collection, index + 1);
                  handler.setProperty(getBean(), getPropertyName(), collection);
              }
  
              ValueUtils.setValue(collection, index, value);
          }
      }
  
      public NodePointer createChild(JXPathContext context, QName name, int index){
          // Ignore the name passed to us, use our own data
          Object collection = getBaseValue();
          if (collection == null){
              AbstractFactory factory = getAbstractFactory(context);
              if (!factory.createObject(context, this, getBean(), getPropertyName(), 0)){
                  throw new RuntimeException("Factory could not create an object for path: " + asPath());
              }
              collection = getBaseValue();
          }
  
          if (index < 0){
              throw new RuntimeException("Index is less than 1: " + asPath());
          }
  
          if (index >= getLength()){
              collection = ValueUtils.expandCollection(collection, index + 1);
              handler.setProperty(getBean(), getPropertyName(), collection);
          }
  
          DynamicPropertyPointer pointer = (DynamicPropertyPointer)this.clone();
          pointer.setIndex(index);
          return pointer;
      }
  
      public NodePointer createPath(JXPathContext context){
          if (getValue() == null){
              AbstractFactory factory = getAbstractFactory(context);
              int inx = (index == WHOLE_COLLECTION ? 0 : index);
              if (!factory.createObject(context, this, getBean(), getPropertyName(), inx)){
                  throw new RuntimeException("Factory could not create an object for path: " + asPath());
              }
          }
          return this;
      }
  
      public String asPath(){
          StringBuffer buffer = new StringBuffer();
          buffer.append(getParent().asPath());
          buffer.append("[@name='");
          buffer.append(escape(getPropertyName()));
          buffer.append("']");
          if (index != WHOLE_COLLECTION && isCollection()){
              buffer.append('[').append(index + 1).append(']');
          }
          return buffer.toString();
      }
  
      private String escape(String string){
          int index = string.indexOf('\'');
          while (index != -1){
              string = string.substring(0, index) + "&apos;" + string.substring(index + 1);
              index = string.indexOf('\'');
          }
          index = string.indexOf('\"');
          while (index != -1){
              string = string.substring(0, index) + "&quot;" + string.substring(index + 1);
              index = string.indexOf('\"');
          }
          return string;
      }
  
      private AbstractFactory getAbstractFactory(JXPathContext context){
          AbstractFactory factory = context.getFactory();
          if (factory == null){
              throw new RuntimeException("Factory is not set on the JXPathContext - cannot create path: " + asPath());
          }
          return factory;
      }
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/LangAttributePointer.java
  
  Index: LangAttributePointer.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/LangAttributePointer.java,v 1.1 2002/04/21 21:52:33 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:33 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model.beans;
  
  import org.apache.commons.jxpath.ri.*;
  import org.apache.commons.jxpath.ri.compiler.*;
  import org.apache.commons.jxpath.ri.model.NodePointer;
  
  import java.util.*;
  
  /**
   * A Pointer that points to the "lang" attribute of a JavaBean. The value
   * of the attribute is based on the locale supplied to it in the constructor.
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:33 $
   */
  public class LangAttributePointer extends NodePointer {
      public LangAttributePointer(NodePointer parent){
          super(parent);
      }
  
      public QName getName(){
          return new QName(null, "lang");
      }
  
      public QName getExpandedName(){
          return getName();
      }
  
      public String getNamespaceURI(){
          return null;
      }
  
      public Object getBaseValue(){
          return parent.getLocale().toString().replace('_', '-');
      }
  
      public Object getValue(){
          return getBaseValue();
      }
  
      public boolean isLeaf(){
          return true;
      }
  
      /**
       * Throws UnsupportedOperationException.
       */
      public void setValue(Object value){
          throw new UnsupportedOperationException("Cannot change locale using the 'lang' attribute");
      }
  
      /**
       */
      public String asPath(){
          StringBuffer buffer = new StringBuffer();
          if (parent != null){
              buffer.append(parent.asPath());
              buffer.append('/');
          }
          buffer.append("@xml:lang");
          return buffer.toString();
      }
  
      public int hashCode(){
          return 0;
      }
  
      public boolean equals(Object object){
          if (object == this){
              return true;
          }
  
          if (!(object instanceof LangAttributePointer)){
              return false;
          }
  
          return true;
      }
  
      public boolean testNode(NodeTest test){
          return false;
      }
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/NullElementPointer.java
  
  Index: NullElementPointer.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/NullElementPointer.java,v 1.1 2002/04/21 21:52:33 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:33 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model.beans;
  
  import org.apache.commons.jxpath.*;
  import org.apache.commons.jxpath.ri.*;
  import org.apache.commons.jxpath.ri.Compiler;
  import org.apache.commons.jxpath.ri.compiler.*;
  import org.apache.commons.jxpath.ri.model.NodePointer;
  import org.apache.commons.jxpath.ri.model.beans.*;
  
  import java.lang.reflect.*;
  import java.util.*;
  import java.beans.*;
  
  /**
   * Used when there is a need to construct a Pointer for
   * a collection element that does not exist.  For example,
   * if the path is "foo[3]", but the collection "foo" only has
   * one element or is empty or is null, the NullElementPointer
   * can be used to capture this situatuin without putting
   * a regular NodePointer into an invalid state.  Just create
   * a NullElementPointer with index 2 (= 3 - 1) and a "foo" pointer
   * as the parent.
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:33 $
   */
  public class NullElementPointer extends PropertyOwnerPointer {
  
      public NullElementPointer(NodePointer parent, int index){
          super(parent);
          this.index = index;
      }
  
      public QName getName(){
          return null;
      }
  
      public Object getBaseValue(){
          return null;
      }
  
      public Object getValue(){
          return null;
      }
  
      public PropertyPointer getPropertyPointer(){
          return new NullPropertyPointer(this);
      }
  
      public NodePointer getValuePointer(){
          return new NullPointer(this, getName());
      }
  
      public void setValue(Object value){
          if (parent instanceof PropertyPointer){
              parent.setValue(value);
          }
          else {
              throw new UnsupportedOperationException("Cannot setValue of an object that is not some other object's property");
          }
      }
  
      public boolean isActual(){
          return false;
      }
  
      public boolean isNode(){
          return false;
      }
  
      public void createPath(JXPathContext context, Object value){
          if (parent instanceof PropertyPointer){
              parent.getParent().createChild(context, parent.getName(), index, value);
          }
          else {
              parent.createChild(context, null, index, value);
          }
      }
  
      public NodePointer createPath(JXPathContext context){
          if (parent instanceof PropertyPointer){
              return parent.getParent().createChild(context, parent.getName(), index);
          }
          else {
              return parent.createChild(context, null, index);
          }
      }
  
      public void createChild(JXPathContext context, QName name, int index, Object value){
          if (index != 0 && index != WHOLE_COLLECTION){
              throw new RuntimeException("Internal error. " +
                  "Indexed passed to NullElementPointer.createChild() is not 0: " + index);
          }
          if (parent instanceof PropertyPointer){
              parent.getParent().createChild(context, parent.getName(), getIndex(), value);
          }
          else {
              parent.createChild(context, name, getIndex(), value);
          }
      }
  
      public NodePointer createChild(JXPathContext context, QName name, int index){
          if (index != 0 && index != WHOLE_COLLECTION){
              throw new RuntimeException("Internal error. " +
                  "Indexed passed to NullElementPointer.createChild() is not 0: " + index);
          }
          if (parent instanceof PropertyPointer){
              return parent.getParent().createChild(context, parent.getName(), getIndex());
          }
          else {
              return parent.createChild(context, name, getIndex());
          }
      }
  
      public int hashCode(){
          return getParent().hashCode() + index;
      }
  
      public boolean equals(Object object){
          if (object == this){
              return true;
          }
  
          if (!(object instanceof NullElementPointer)){
              return false;
          }
  
          NullElementPointer other = (NullElementPointer)object;
          return getParent() == other.getParent() &&
              index == other.index;
      }
  
      public String asPath(){
          return parent.asPath() + "[" + (index + 1) + "]";
      }
  
      public int getLength(){
          return 0;
      }
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/NullPointer.java
  
  Index: NullPointer.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/NullPointer.java,v 1.1 2002/04/21 21:52:33 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:33 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model.beans;
  
  import org.apache.commons.jxpath.*;
  import org.apache.commons.jxpath.ri.*;
  import org.apache.commons.jxpath.ri.Compiler;
  import org.apache.commons.jxpath.ri.compiler.*;
  import org.apache.commons.jxpath.ri.model.NodePointer;
  import org.apache.commons.jxpath.ri.model.beans.*;
  
  import java.lang.reflect.*;
  import java.util.*;
  import java.beans.*;
  
  /**
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:33 $
   */
  public class NullPointer extends PropertyOwnerPointer {
      private QName name;
  
      public NullPointer(QName name, Locale locale){
          super(null, locale);
          this.name = name;
      }
  
      /**
       * Used for the root node
       */
      public NullPointer(NodePointer parent, QName name){
          super(parent);
          this.name = name;
      }
  
      public QName getName(){
          return name;
      }
  
      public Object getBaseValue(){
          return null;
      }
  
      public void setValue(Object value){
          if (parent instanceof PropertyPointer){
              parent.setValue(value);
          }
          else {
              throw new UnsupportedOperationException("Cannot setValue of an object that is not some other object's property/child");
          }
      }
  
      public boolean isActual(){
          return false;
      }
  
      public PropertyPointer getPropertyPointer(){
          return new NullPropertyPointer(this);
      }
  
      public void createPath(JXPathContext context, Object value){
          if (parent != null){
              if (parent instanceof PropertyPointer){
                  parent.createPath(context, value);
              }
              else {
                  parent.createChild(context, getName(), 0, value);
              }
          }
          else {
              throw new UnsupportedOperationException("Cannot create the root object: " + asPath());
          }
      }
  
      public NodePointer createPath(JXPathContext context){
          if (parent != null){
              if (parent instanceof PropertyPointer){
                  return parent.createPath(context).getValuePointer();
              }
              else {
                  return parent.createChild(context, getName(), 0).getValuePointer();
              }
          }
          throw new UnsupportedOperationException("Cannot create the root object: " + asPath());
      }
  
      public void createChild(JXPathContext context, QName name, int index, Object value){
          if (parent != null){
              NodePointer pointer = createPath(context);
              if (pointer != null){
                  pointer.getValuePointer().createChild(context, name, index, value);
                  return;
              }
          }
          throw new UnsupportedOperationException("Cannot create the root object: " + asPath());
      }
  
      public NodePointer createChild(JXPathContext context, QName name, int index){
          if (parent != null){
              NodePointer pointer = createPath(context);
              if (pointer != null){
                  return pointer.createChild(context, name, index);
              }
          }
          throw new UnsupportedOperationException("Cannot create the root object: " + asPath());
      }
  
      public int hashCode(){
          return name == null ? 0 : name.hashCode();
      }
  
      public boolean equals(Object object){
          if (object == this){
              return true;
          }
  
          if (!(object instanceof NullPointer)){
              return false;
          }
  
          NullPointer other = (NullPointer)object;
          return (name == null && other.name == null) ||
                 (name != null && name.equals(other.name));
      }
  
      public String asPath(){
          if (parent != null){
              return super.asPath();
          }
          return "null()";
      }
  
      public int getLength(){
          return 0;
      }
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/NullPropertyPointer.java
  
  Index: NullPropertyPointer.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/NullPropertyPointer.java,v 1.1 2002/04/21 21:52:33 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:33 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model.beans;
  
  import org.apache.commons.jxpath.*;
  import org.apache.commons.jxpath.ri.*;
  import org.apache.commons.jxpath.ri.Compiler;
  import org.apache.commons.jxpath.ri.compiler.*;
  import org.apache.commons.jxpath.ri.model.NodePointer;
  import org.apache.commons.jxpath.ri.model.beans.*;
  
  import java.lang.reflect.*;
  import java.util.*;
  import java.beans.*;
  
  /**
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:33 $
   */
  public class NullPropertyPointer extends PropertyPointer {
  
      private String propertyName = "*";
      private boolean dynamic = false;
  
      /**
       */
      public NullPropertyPointer(NodePointer parent){
          super(parent);
      }
  
      public QName getName(){
          return new QName(null, propertyName);
      }
  
      public void setPropertyIndex(int index){
      }
  
      public int getLength(){
          return 0;
      }
  
      public Object getBaseValue(){
          return null;
      }
  
      public Object getValue(){
          return null;
      }
  
      public NodePointer getValuePointer(){
          return new NullPointer(this,  new QName(null, getPropertyName()));
      }
  
      protected boolean isActualProperty(){
          return false;
      }
  
      public boolean isActual(){
          return false;
      }
  
      public boolean isNode(){
          return false;
      }
  
      public void setValue(Object value){
          throw new RuntimeException("Cannot set property " + asPath() +
              ", the target object is null");
      }
  
      public NodePointer createPath(JXPathContext context){
          return parent.createChild(context, getName(), getIndex());
      }
  
      public void createPath(JXPathContext context, Object value){
          parent.createChild(context, getName(), getIndex(), value);
      }
  
      public void createChild(JXPathContext context, QName name, int index, Object value){
          createPath(context).createChild(context, name, index, value);
      }
  
      public NodePointer createChild(JXPathContext context, QName name, int index){
          return createPath(context).createChild(context, name, index);
      }
  
      public String getPropertyName(){
          return propertyName;
      }
  
      public void setPropertyName(String propertyName){
          this.propertyName = propertyName;
      }
  
      public void setDynamic(boolean flag){
          dynamic = flag;
      }
  
      public boolean isCollection(){
          return getIndex() != WHOLE_COLLECTION;
      }
  
      public int getPropertyCount(){
          return 0;
      }
  
      public String[] getPropertyNames(){
          return new String[0];
      }
  
      public String asPath(){
          if (!dynamic){
              return super.asPath();
          }
          else {
              StringBuffer buffer = new StringBuffer();
              buffer.append(getParent().asPath());
              buffer.append("[@name='");
              buffer.append(escape(getPropertyName()));
              buffer.append("']");
              if (index != WHOLE_COLLECTION){
                  buffer.append('[').append(index + 1).append(']');
              }
              return buffer.toString();
          }
      }
  
      private String escape(String string){
          int index = string.indexOf('\'');
          while (index != -1){
              string = string.substring(0, index) + "&apos;" + string.substring(index + 1);
              index = string.indexOf('\'');
          }
          index = string.indexOf('\"');
          while (index != -1){
              string = string.substring(0, index) + "&quot;" + string.substring(index + 1);
              index = string.indexOf('\"');
          }
          return string;
      }
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/PropertyIterator.java
  
  Index: PropertyIterator.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/PropertyIterator.java,v 1.1 2002/04/21 21:52:33 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:33 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model.beans;
  
  import org.apache.commons.jxpath.ri.model.NodeIterator;
  import org.apache.commons.jxpath.ri.model.NodePointer;
  
  /**
   * Iterates property values of an object pointed at with a PropertyOwnerPointer.
   * Examples of such objects are JavaBeans and objects with Dynamic Properties.
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:33 $
   */
  public class PropertyIterator implements NodeIterator {
      boolean empty = false;
      private boolean reverse;
      private String name;
      private int startIndex = 0;
      private boolean targetReady = false;
      private int position = 0;
      private PropertyPointer propertyNodePointer;
      private int startPropertyIndex;
  
      private boolean ready = false;
      private boolean includeStart = false;
  
      public PropertyIterator(PropertyOwnerPointer pointer, String name, boolean reverse, NodePointer startWith){
          propertyNodePointer = pointer.getPropertyPointer();
          this.name = name;
          this.reverse = reverse;
          this.includeStart = true;
          if (reverse){
              this.startPropertyIndex = PropertyPointer.UNSPECIFIED_PROPERTY;
              this.startIndex = -1;
          }
          if (startWith != null){
              while (startWith != null && startWith.getParent() != pointer){
                  startWith = startWith.getParent();
              }
              if (startWith == null){
                  throw new RuntimeException(
                      "PropertyIerator startWith parameter is not a child of the supplied parent");
              }
              this.startPropertyIndex = ((PropertyPointer)startWith).getPropertyIndex();
              this.startIndex = startWith.getIndex();
              this.includeStart = false;
              if (reverse && startIndex == -1){
                  this.includeStart = true;
              }
          }
      }
  
      public void reset(){
          position = 0;
          targetReady = false;
      }
  
      public NodePointer getNodePointer(){
          if (position == 0){
              if (name != null){
                  if (!targetReady){
                      prepare();
                  }
                  // If there is no such property - return null
                  if (empty){
                      return null;
                  }
              }
              else {
                  if (!setPosition(1)){
                      return null;
                  }
                  reset();
              }
          }
          return propertyNodePointer.getValuePointer();
      }
  
      public int getPosition(){
          return position;
      }
  
      public boolean setPosition(int position){
          if (name != null){
              return setPositionIndividualProperty(position);
          }
          else {
              return setPositionAllProperties(position);
          }
      }
  
      private boolean setPositionIndividualProperty(int position){
          this.position = position;
          if (position < 1){
              return false;
          }
  
          if (!targetReady){
              prepare();
          }
  
          if (empty){
              return false;
          }
  
          int length = propertyNodePointer.getLength();   // TBD: cache length
          int index;
          if (!reverse){
              index = position + startIndex;
              if (!includeStart){
                  index++;
              }
              if (index > length){
                  return false;
              }
          }
          else {
              int end = startIndex;
              if (end == -1){
                  end = length - 1;
              }
              index = end - position + 2;
              if (!includeStart){
                  index--;
              }
              if (index < 1){
                  return false;
              }
          }
          propertyNodePointer.setIndex(index - 1);
          return true;
      }
  
      private boolean setPositionAllProperties(int position){
          this.position = position;
          if (position < 1){
              return false;
          }
  
          int offset;
          int count = propertyNodePointer.getPropertyCount();
          if (!reverse){
              int index = 1;
              for (int i = startPropertyIndex; i < count; i++){
                  propertyNodePointer.setPropertyIndex(i);
                  int length = propertyNodePointer.getLength();
                  if (i == startPropertyIndex){
                      length -= startIndex;
                      if (!includeStart){
                          length--;
                      }
                      offset = startIndex + position - index;
                      if (!includeStart){
                          offset++;
                      }
                  }
                  else {
                      offset = position - index;
                  }
                  if (index <= position && position < index + length){
                      propertyNodePointer.setIndex(offset);
                      return true;
                  }
                  index += length;
              }
          }
          else {
              int index = 1;
              int start = startPropertyIndex;
              if (start == PropertyPointer.UNSPECIFIED_PROPERTY){
                  start = count - 1;
              }
              for (int i = start; i >= 0; i--){
                  propertyNodePointer.setPropertyIndex(i);
                  int length = propertyNodePointer.getLength();
                  if (i == startPropertyIndex){
                      int end = startIndex;
                      if (end == -1){
                          end = length - 1;
                      }
                      length = end + 1;
                      offset = end - position + 1;
                      if (!includeStart){
                          offset--;
                          length--;
                      }
                  }
                  else {
                      offset = length - (position - index) - 1;
                  }
  
                  if (index <= position && position < index + length){
                      propertyNodePointer.setIndex(offset);
                      return true;
                  }
                  index += length;
              }
          }
          return false;
      }
  
      private void prepare(){
          targetReady = true;
          empty = true;
          // TBD: simplify
          if (propertyNodePointer instanceof DynamicPropertyPointer){
              propertyNodePointer.setPropertyName(name);
          }
  
          String names[] = propertyNodePointer.getPropertyNames();
          if (!reverse){
  //            int startPropertyIndex = propertyNodePointer.getPropertyIndex();
              if (startPropertyIndex == PropertyPointer.UNSPECIFIED_PROPERTY){
                  startPropertyIndex = 0;
              }
              if (startIndex == NodePointer.WHOLE_COLLECTION){
                  startIndex = 0;
              }
              for (int i = startPropertyIndex; i < names.length; i++){
                  if (names[i].equals(name)){
                      propertyNodePointer.setPropertyIndex(i);
                      if (i != startPropertyIndex){
                          startIndex = 0;
                          includeStart = true;
                      }
                      empty = false;
                      break;
                  }
              }
          }
          else {
  //            int startPropertyIndex = propertyNodePointer.getPropertyIndex();
              if (startPropertyIndex == PropertyPointer.UNSPECIFIED_PROPERTY){
                  startPropertyIndex = names.length - 1;
              }
              if (startIndex == NodePointer.WHOLE_COLLECTION){
                  startIndex = -1;
              }
              for (int i = startPropertyIndex; i >= 0; i--){
                  if (names[i].equals(name)){
                      propertyNodePointer.setPropertyIndex(i);
                      if (i != startPropertyIndex){
                          startIndex = -1;
                          includeStart = true;
                      }
                      empty = false;
                      break;
                  }
              }
          }
      }
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/PropertyOwnerPointer.java
  
  Index: PropertyOwnerPointer.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/PropertyOwnerPointer.java,v 1.1 2002/04/21 21:52:33 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:33 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model.beans;
  
  import org.apache.commons.jxpath.*;
  import org.apache.commons.jxpath.ri.*;
  import org.apache.commons.jxpath.ri.Compiler;
  import org.apache.commons.jxpath.ri.compiler.*;
  import org.apache.commons.jxpath.ri.model.*;
  import org.apache.commons.jxpath.ri.model.NodeIterator;
  import org.apache.commons.jxpath.ri.model.NodePointer;
  import org.apache.commons.jxpath.util.*;
  
  import java.util.*;
  
  
  /**
   * A pointer describing a node that has properties, each of which could be
   * a collection.
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:33 $
   */
  public abstract class PropertyOwnerPointer extends NodePointer {
  
      public NodeIterator childIterator(NodeTest test, boolean reverse, NodePointer startWith){
          if (test == null){
              return new PropertyIterator(this, null, reverse, startWith);
          }
          else if (test instanceof NodeNameTest){
              QName testName = ((NodeNameTest)test).getNodeName();
              String property;
              if (!isDefaultNamespace(testName.getPrefix())){
                  return null;
              }
              else if (testName.getName().equals("*")){
                  property = null;
              }
              else {
                  property = testName.getName();
              }
              return new PropertyIterator(this, property, reverse, startWith);
          }
          else if (test instanceof NodeTypeTest){
              if (((NodeTypeTest)test).getNodeType() == Compiler.NODE_TYPE_NODE){
                  return new PropertyIterator(this, null, reverse, startWith);
              }
          }
          return null;
      }
  
      public NodeIterator attributeIterator(QName name){
          return new BeanAttributeIterator(this, name);
      }
  
      protected PropertyOwnerPointer(NodePointer parent, Locale locale){
          super(parent, locale);
      }
  
      protected PropertyOwnerPointer(NodePointer parent){
          super(parent);
      }
  
      public boolean isCollection(){
          Object value = getBaseValue();
          return value != null && ValueUtils.isCollection(value);
      }
  
      public void setIndex(int index){
          if (this.index != index){
              super.setIndex(index);
              value = UNINITIALIZED;
          }
      }
  
      private static final Object UNINITIALIZED = new Object();
  
      private Object value = UNINITIALIZED;
      public Object getValue(){
          if (value == UNINITIALIZED){
              if (index == WHOLE_COLLECTION){
                  value = getBaseValue();
              }
              else {
                  value = ValueUtils.getValue(getBaseValue(), index);
              }
          }
          return value;
      }
  
      public abstract QName getName();
      public abstract void setValue(Object value);
  
      public abstract PropertyPointer getPropertyPointer();
  
      /**
       * If has an index, returns a pointer to the collection element,
       * otherwise returns the pointer itself.
       */
      public NodePointer getValuePointer() {
          return NodePointer.newChildNodePointer(this, getName(), getValue());
      }
  
      public void createChild(JXPathContext context, QName name, int index, Object value){
          PropertyPointer prop = getPropertyPointer();
          prop.setPropertyName(name.getName());
          prop.setIndex(index);
          prop.createPath(context, value);
      }
  
      public NodePointer createChild(JXPathContext context, QName name, int index){
          PropertyPointer prop = getPropertyPointer();
          prop.setPropertyName(name.getName());
          prop.setIndex(index);
          return prop.createPath(context);
      }
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/PropertyPointer.java
  
  Index: PropertyPointer.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/PropertyPointer.java,v 1.1 2002/04/21 21:52:33 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:33 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model.beans;
  
  import org.apache.commons.jxpath.*;
  import org.apache.commons.jxpath.ri.*;
  import org.apache.commons.jxpath.ri.compiler.*;
  import org.apache.commons.jxpath.ri.model.*;
  import org.apache.commons.jxpath.ri.model.NodePointer;
  import org.apache.commons.jxpath.util.*;
  
  import java.util.*;
  
  /**
   * A pointer allocated by a PropertyOwnerPointer to represent the value of
   * a property of the parent object.
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:33 $
   */
  public abstract class PropertyPointer extends NodePointer {
      public static int UNSPECIFIED_PROPERTY = Integer.MIN_VALUE;
  
      protected int propertyIndex = UNSPECIFIED_PROPERTY;
      protected Object bean;
  
      /**
       * Takes a javabean, a descriptor of a property of that object and
       * an offset within that property (starting with 0).
       */
      public PropertyPointer(NodePointer parent){
          super(parent);
      }
  
      public boolean isCollection(){
          Object value = getBaseValue();
          return value != null && ValueUtils.isCollection(value);
      }
  
      public int getPropertyIndex(){
          return propertyIndex;
      }
  
      public void setPropertyIndex(int index){
          propertyIndex = index;
          index = WHOLE_COLLECTION;
      }
  
      public Object getBean(){
          if (bean == null){
              bean = getParent().getValue();
          }
          return bean;
      }
  
      public QName getName(){
          return new QName(null, getPropertyName());
      }
  
      public abstract String getPropertyName();
  
      public abstract void setPropertyName(String propertyName);
  
      public abstract int getPropertyCount();
  
      public abstract String[] getPropertyNames();
  
      protected abstract boolean isActualProperty();
  
      public boolean isActual(){
          if (!isActualProperty()){
              return false;
          }
  
          return super.isActual();
      }
  
      private static final Object UNINITIALIZED = new Object();
  
      private Object value = UNINITIALIZED;
      public Object getValue(){
          if (value == UNINITIALIZED){
              if (index == WHOLE_COLLECTION){
                  value = getBaseValue();
              }
              else {
                  value = ValueUtils.getValue(getBaseValue(), index);
              }
          }
          return value;
      }
  
      /**
       * Returns a NodePointer that can be used to access the currently
       * selected property value.
       */
      public NodePointer getValuePointer(){
          return NodePointer.newChildNodePointer(this, getName(), getValue());
      }
  
      public int hashCode(){
          return getParent().hashCode() + propertyIndex + index;
      }
  
      public boolean equals(Object object){
          if (object == this){
              return true;
          }
  
          if (!(object instanceof PropertyPointer)){
              return false;
          }
  
          PropertyPointer other = (PropertyPointer)object;
          return getParent() == other.getParent() &&
                  propertyIndex == other.propertyIndex &&
                  index == other.index;
      }
  
      public String toString(){
          StringBuffer buffer = new StringBuffer();
          if (getBean() == null){
              buffer.append("null");
          }
          else {
              buffer.append(getBean().getClass().getName());
          }
          buffer.append('@');
          buffer.append(System.identityHashCode(getBean()));
          buffer.append('.');
          buffer.append(getPropertyName());
          if (index != WHOLE_COLLECTION){
              buffer.append('[').append(index).append(']');
          }
          buffer.append(" = ").append(getValue());
          return buffer.toString();
      }
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/beans/package.html
  
  Index: package.html
  ===================================================================
  <body>
  Implementation of "model" APIs for JavaBeans, Dynamic Property Objects,
  collections and null.
  </body>
  
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/container/ContainerPointer.java
  
  Index: ContainerPointer.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/container/ContainerPointer.java,v 1.1 2002/04/21 21:52:33 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:33 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model.container;
  
  import java.util.Locale;
  
  import org.apache.commons.jxpath.Container;
  import org.apache.commons.jxpath.ri.QName;
  import org.apache.commons.jxpath.ri.compiler.NodeTest;
  import org.apache.commons.jxpath.ri.model.NodeIterator;
  import org.apache.commons.jxpath.ri.model.NodePointer;
  import org.apache.commons.jxpath.util.ValueUtils;
  
  /**
   * Transparent pointer to a Container. The getValue() method
   * returns the contents of the container, rather than the container
   * itself.
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:33 $
   */
  public class ContainerPointer extends NodePointer {
      private Container container;
      private NodePointer valuePointer;
  
      public ContainerPointer(Container container, Locale locale){
          super(null, locale);
          this.container = container;
      }
  
      public ContainerPointer(NodePointer parent, Container container){
          super(parent);
          this.container = container;
      }
  
      /**
       * This type of node is auxiliary.
       */
      public boolean isNode(){
          return false;
      }
  
      public QName getName(){
          return null;
      }
  
      public Object getBaseValue(){
          return container.getValue();
      }
  
      public Object getValue(){
          Object value = getBaseValue();
          if (index != WHOLE_COLLECTION){
              return ValueUtils.getValue(value, index);
          }
          return value;
      }
  
      public void setValue(Object value){
          container.setValue(value);
      }
  
      public NodePointer getValuePointer(){
          if (valuePointer == null){
              Object value = getValue();
              valuePointer = NodePointer.newChildNodePointer(this, getName(), value).getValuePointer();
          }
          return valuePointer;
      }
  
      public int hashCode(){
          return System.identityHashCode(container) + index;
      }
  
      public boolean equals(Object object){
          if (object == this){
              return true;
          }
  
          if (!(object instanceof ContainerPointer)){
              return false;
          }
  
          ContainerPointer other = (ContainerPointer)object;
          return container == other.container &&
                  index == other.index;
      }
  
      public NodeIterator childIterator(NodeTest test, boolean reverse, NodePointer startWith){
          return getValuePointer().childIterator(test, reverse, startWith);
      }
  
      public NodeIterator attributeIterator(QName name){
          return getValuePointer().attributeIterator(name);
      }
  
      public NodeIterator namespaceIterator(){
          return getValuePointer().namespaceIterator();
      }
  
      public NodePointer namespacePointer(String namespace){
          return getValuePointer().namespacePointer(namespace);
      }
  
      public boolean testNode(NodeTest nodeTest){
          return getValuePointer().testNode(nodeTest);
      }
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/container/ContainerPointerFactory.java
  
  Index: ContainerPointerFactory.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/container/ContainerPointerFactory.java,v 1.1 2002/04/21 21:52:33 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:33 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model.container;
  
  import org.apache.commons.jxpath.Container;
  import org.apache.commons.jxpath.ri.QName;
  import org.apache.commons.jxpath.ri.model.NodePointer;
  import org.apache.commons.jxpath.ri.model.NodePointerFactory;
  
  import java.util.*;
  
  /**
   * Implements NodePointerFactory for Container objects.
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:33 $
   */
  public class ContainerPointerFactory implements NodePointerFactory {
  
      public static final int CONTAINER_POINTER_FACTORY_ORDER = 200;
  
      public int getOrder(){
          return CONTAINER_POINTER_FACTORY_ORDER;
      }
  
      public NodePointer createNodePointer(QName name, Object bean, Locale locale){
          if (bean instanceof Container){
              return new ContainerPointer((Container)bean, locale);
          }
          return null;
      }
  
      public NodePointer createNodePointer(NodePointer parent, QName name, Object bean){
          if (bean instanceof Container){
              return new ContainerPointer(parent, (Container)bean);
          }
          return null;
      }
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/container/package.html
  
  Index: package.html
  ===================================================================
  <body>
  Implementation of "model" APIs for Containers.
  </body>
  
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/dom/DOMAttributeIterator.java
  
  Index: DOMAttributeIterator.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/dom/DOMAttributeIterator.java,v 1.1 2002/04/21 21:52:33 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:33 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model.dom;
  
  import org.apache.commons.jxpath.*;
  import org.apache.commons.jxpath.ri.*;
  import org.apache.commons.jxpath.ri.Compiler;
  import org.apache.commons.jxpath.ri.compiler.*;
  import org.apache.commons.jxpath.ri.model.NodeIterator;
  import org.apache.commons.jxpath.ri.model.NodePointer;
  
  import java.lang.reflect.*;
  import java.util.*;
  import java.beans.*;
  import org.w3c.dom.*;
  
  /**
   * An iterator of attributes of a DOM Node.
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:33 $
   */
  public class DOMAttributeIterator implements NodeIterator {
      private NodePointer parent;
      private QName name;
      private List attributes;
      private int position = 0;
  
      public DOMAttributeIterator(NodePointer parent, QName name){
          this.parent = parent;
          this.name = name;
          attributes = new ArrayList();
          Node node = (Node)parent.getValue();
          if (node.getNodeType() == Node.ELEMENT_NODE){
              String lname = name.getName();
              if (!lname.equals("*")){
                  Attr attr = getAttribute((Element)node, name);
                  if (attr != null){
                      attributes.add(attr);
                  }
              }
              else {
                  NamedNodeMap map = node.getAttributes();
                  int count = map.getLength();
                  for (int i = 0; i < count; i++){
                      Attr attr = (Attr)map.item(i);
                      if (testAttr(attr, name)){
                          attributes.add(attr);
                      }
                  }
              }
          }
      }
  
      private boolean testAttr(Attr attr, QName testName){
          String nodePrefix = DOMNodePointer.getPrefix(attr);
          String nodeLocalName = DOMNodePointer.getLocalName(attr);
  
          if (nodePrefix != null && nodePrefix.equals("xmlns")){
              return false;
          }
  
          if (nodePrefix == null && nodeLocalName.equals("xmlns")){
              return false;
          }
  
          String testLocalName = name.getName();
          if (testLocalName.equals("*") || testLocalName.equals(nodeLocalName)){
              String testPrefix = testName.getPrefix();
  
              if (equalStrings(testPrefix, nodePrefix)){
                  return true;
              }
  
              String testNS = null;
              if (testPrefix != null){
                  testNS = parent.getNamespaceURI(testPrefix);
              }
  
              String nodeNS = null;
              if (nodePrefix != null){
                  nodeNS = parent.getNamespaceURI(nodePrefix);
              }
              return equalStrings(testNS, nodeNS);
          }
          return false;
      }
  
      private static boolean equalStrings(String s1, String s2){
          if (s1 == null && s2 != null){
              return false;
          }
          if (s1 != null && !s1.equals(s2)){
              return false;
          }
          return true;
      }
  
      private Attr getAttribute(Element element, QName name){
          String testPrefix = name.getPrefix();
          String testNS = null;
  
          if (testPrefix != null){
              testNS = parent.getNamespaceURI(testPrefix);
          }
  
          Node attr;
          if (testNS != null){
              return element.getAttributeNodeNS(testNS, name.getName());
          }
          else {
              return element.getAttributeNode(name.getName());
          }
      }
  
      public NodePointer getNodePointer(){
          if (position == 0){
              if (!setPosition(1)){
                  return null;
              }
              position = 0;
          }
          int index = position - 1;
          if (index < 0){
              index = 0;
          }
          return new DOMAttributePointer(parent, (Attr)attributes.get(index));
      }
  
      public int getPosition(){
          return position;
      }
  
      public boolean setPosition(int position){
          this.position = position;
          return position >= 1 && position <= attributes.size();
      }
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/dom/DOMAttributePointer.java
  
  Index: DOMAttributePointer.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/dom/DOMAttributePointer.java,v 1.1 2002/04/21 21:52:33 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:33 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model.dom;
  
  import org.apache.commons.jxpath.*;
  import org.apache.commons.jxpath.ri.*;
  import org.apache.commons.jxpath.ri.Compiler;
  import org.apache.commons.jxpath.ri.compiler.*;
  import org.apache.commons.jxpath.ri.model.NodePointer;
  
  import java.lang.reflect.*;
  import java.util.*;
  import java.beans.*;
  import org.w3c.dom.*;
  import org.apache.commons.jxpath.util.TypeUtils;
  
  /**
   * A Pointer that points to a DOM node.
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:33 $
   */
  public class DOMAttributePointer extends NodePointer {
      private Attr attr;
  
      public DOMAttributePointer(NodePointer parent, Attr attr){
          super(parent);
          this.attr = attr;
      }
  
      public QName getName(){
          return new QName(DOMNodePointer.getPrefix(attr), DOMNodePointer.getLocalName(attr));
      }
  
      public QName getExpandedName(){
          return new QName(getNamespaceURI(),  DOMNodePointer.getLocalName(attr));
      }
  
      public String getNamespaceURI(){
          String prefix = DOMNodePointer.getPrefix(attr);
          if (prefix == null){
              return null;
          }
          return parent.getNamespaceURI(prefix);
      }
  
      public Object getBaseValue(){
          return attr;
      }
  
      public Object getValue(){
          String value = attr.getValue();
          if (value == null){
              return null;
          }
          if (value.equals("") && !attr.getSpecified()){
              return null;
          }
          return value;
      }
  
      public boolean isActual(){
          return true;
      }
  
      public boolean isLeaf(){
          return true;
      }
  
      public boolean testNode(NodeTest nodeTest){
          return nodeTest == null ||
                  ((nodeTest instanceof NodeTypeTest) &&
                      ((NodeTypeTest)nodeTest).getNodeType() == Compiler.NODE_TYPE_NODE);
      }
  
      /**
       * Sets the value of this attribute.
       */
      public void setValue(Object value){
          attr.setValue((String)TypeUtils.convert(value, String.class));
      }
  
      /**
       */
      public String asPath(){
          StringBuffer buffer = new StringBuffer();
          if (parent != null){
              buffer.append(parent.asPath());
              buffer.append('/');
          }
          buffer.append('@');
          buffer.append(getName());
          return buffer.toString();
      }
  
      public int hashCode(){
          return System.identityHashCode(attr);
      }
  
      public boolean equals(Object object){
          if (object == this){
              return true;
          }
  
          if (!(object instanceof DOMAttributePointer)){
              return false;
          }
  
          DOMAttributePointer other = (DOMAttributePointer)object;
          return attr == other.attr;
      }
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/dom/DOMNamespaceIterator.java
  
  Index: DOMNamespaceIterator.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/dom/DOMNamespaceIterator.java,v 1.1 2002/04/21 21:52:33 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:33 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model.dom;
  
  import org.apache.commons.jxpath.*;
  import org.apache.commons.jxpath.ri.Compiler;
  import org.apache.commons.jxpath.ri.compiler.*;
  import org.apache.commons.jxpath.ri.model.NodeIterator;
  import org.apache.commons.jxpath.ri.model.NodePointer;
  
  import java.lang.reflect.*;
  import java.util.*;
  import java.beans.*;
  import org.w3c.dom.*;
  
  /**
   * An iterator of namespaces of a DOM Node.
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:33 $
   */
  public class DOMNamespaceIterator implements NodeIterator {
      private NodePointer parent;
      private List attributes;
      private int position = 0;
  
      public DOMNamespaceIterator(NodePointer parent){
          this.parent = parent;
          attributes = new ArrayList();
          collectNamespaces(attributes, (Node)parent.getValue());
      }
  
      private void collectNamespaces(List attributes, Node node){
          Node parent = node.getParentNode();
          if (parent != null){
              collectNamespaces(attributes, parent);
          }
          if (node.getNodeType() == Node.ELEMENT_NODE){
              NamedNodeMap map = node.getAttributes();
              int count = map.getLength();
              for (int i = 0; i < count; i++){
                  Attr attr = (Attr)map.item(i);
                  String prefix = DOMNodePointer.getPrefix(attr);
                  String name = DOMNodePointer.getLocalName(attr);
                  if ((prefix != null && prefix.equals("xmlns")) ||
                          (prefix == null && name.equals("xmlns"))){
                      attributes.add(attr);
                  }
              }
          }
      }
  
      public NodePointer getNodePointer(){
          if (position == 0){
              if (!setPosition(1)){
                  return null;
              }
              position = 0;
          }
          int index = position - 1;
          if (index < 0){
              index = 0;
          }
          String prefix = "";
          Attr attr = (Attr)attributes.get(index);
          String name = attr.getPrefix();
          if (name != null && name.equals("xmlns")){
              prefix = DOMNodePointer.getLocalName(attr);
          }
          return new NamespacePointer(parent, prefix, attr.getValue());
      }
  
      public int getPosition(){
          return position;
      }
  
      public boolean setPosition(int position){
          this.position = position;
          return position >= 1 && position <= attributes.size();
      }
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/dom/DOMNodeIterator.java
  
  Index: DOMNodeIterator.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/dom/DOMNodeIterator.java,v 1.1 2002/04/21 21:52:33 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:33 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model.dom;
  
  import org.apache.commons.jxpath.*;
  import org.apache.commons.jxpath.ri.Compiler;
  import org.apache.commons.jxpath.ri.compiler.*;
  import org.apache.commons.jxpath.ri.model.NodeIterator;
  import org.apache.commons.jxpath.ri.model.NodePointer;
  
  import java.lang.reflect.*;
  import java.util.*;
  import java.beans.*;
  import org.w3c.dom.*;
  
  /**
   * An iterator of children of a DOM Node.
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:33 $
   */
  public class DOMNodeIterator implements NodeIterator {
      private NodePointer parent;
      private NodeTest nodeTest;
      private String namespaceURI;
      private Node node;
      private Node child = null;
      private boolean reverse;
      private int position = 0;
  
      public DOMNodeIterator(NodePointer parent, NodeTest nodeTest, boolean reverse, NodePointer startWith){
          this.parent = parent;
          this.node = (Node)parent.getValue();
          if (startWith != null){
              this.child = (Node)startWith.getValue();
          }
          this.nodeTest = nodeTest;
          this.reverse = reverse;
      }
  
      public NodePointer getNodePointer(){
          if (child == null){
              if (!setPosition(1)){
                  return null;
              }
              position = 0;
          }
  
          return new DOMNodePointer(parent, child);
      }
  
      public int getPosition(){
          return position;
      }
  
      public boolean setPosition(int position){
          while (this.position < position){
              if (!next()){
                  return false;
              }
          }
          while (this.position > position){
              if (!previous()){
                  return false;
              }
          }
  //        System.err.println(getNodePointer().asPath() + " SET POSITION: " + position);
          return true;
      }
  
      private boolean previous(){
          position--;
          if (!reverse){
              child = child.getPreviousSibling();
              while (child != null && !testChild()){
                  child = child.getPreviousSibling();
              }
          }
          else {
              child = child.getNextSibling();
              while (child != null && !testChild()){
                  child = child.getNextSibling();
              }
          }
          return child != null;
      }
  
      private boolean next(){
          position++;
          if (!reverse){
              if (position == 1){
                  if (child == null){
                      child = node.getFirstChild();
                  }
                  else {
                      child = child.getNextSibling();
                  }
              }
              else {
                  child = child.getNextSibling();
              }
              while (child != null && !testChild()){
                  child = child.getNextSibling();
              }
          }
          else {
              if (position == 1){
                  if (child == null){
                      child = node.getLastChild();
                  }
                  else {
                      child = child.getPreviousSibling();
                  }
              }
              else {
                  child = child.getPreviousSibling();
              }
              while (child != null && !testChild()){
                  child = child.getPreviousSibling();
              }
          }
          return child != null;
      }
  
      private boolean testChild(){
          return DOMNodePointer.testNode(parent, child, nodeTest);
      }
  /*
      public NodePointer getNodePointer(){
          if (child == null){
              if (!setPosition(1)){
                  return null;
              }
              position = 0;
          }
  
          if (children){
              return new DOMNodePointer(parent, child);
          }
          else {
              return new DOMNodePointer(parent.getParent(), child);
          }
      }
  
      public int getPosition(){
          return position;
      }
  
      public boolean setPosition(int position){
          while (this.position < position){
              if (!next()){
                  return false;
              }
          }
          while (this.position > position){
              if (!previous()){
                  return false;
              }
          }
  //        System.err.println(getNodePointer().asPath() + " SET POSITION: " + position);
          return true;
      }
  
      private boolean previous(){
          position--;
          if (!reverse){
              child = child.getPreviousSibling();
              while (child != null && !testChild()){
                  child = child.getPreviousSibling();
              }
          }
          else {
              child = child.getNextSibling();
              while (child != null && !testChild()){
                  child = child.getNextSibling();
              }
          }
          return child != null;
      }
  
      private boolean next(){
          position++;
          if (!reverse){
              if (position == 1){
                  if (children){
                      child = node.getFirstChild();
                  }
                  else {
                      child = node.getNextSibling();
                  }
              }
              else {
                  child = child.getNextSibling();
              }
              while (child != null && !testChild()){
                  child = child.getNextSibling();
              }
          }
          else {
              if (position == 1){
                  if (children){
                      child = node.getLastChild();
                  }
                  else {
                      child = node.getPreviousSibling();
                  }
              }
              else {
                  child = child.getPreviousSibling();
              }
              while (child != null && !testChild()){
                  child = child.getPreviousSibling();
              }
          }
          return child != null;
      }
  
      private boolean testChild(){
          return DOMNodePointer.testNode(parent, child, nodeTest);
      }
      */
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/dom/DOMNodePointer.java
  
  Index: DOMNodePointer.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/dom/DOMNodePointer.java,v 1.1 2002/04/21 21:52:33 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:33 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model.dom;
  
  import org.apache.commons.jxpath.*;
  import org.apache.commons.jxpath.ri.*;
  import org.apache.commons.jxpath.ri.Compiler;
  import org.apache.commons.jxpath.ri.compiler.*;
  import org.apache.commons.jxpath.ri.model.NodeIterator;
  import org.apache.commons.jxpath.ri.model.NodePointer;
  
  import java.lang.reflect.*;
  import java.util.*;
  import java.beans.*;
  import org.w3c.dom.*;
  import org.apache.commons.jxpath.util.TypeUtils;
  
  /**
   * A Pointer that points to a DOM node.
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:33 $
   */
  public class DOMNodePointer extends NodePointer {
      private Node node;
      private Map namespaces;
      private String defaultNamespace;
  
      public static final String XML_NAMESPACE_URI = "http://www.w3.org/XML/1998/namespace";
      public static final String XMLNS_NAMESPACE_URI = "http://www.w3.org/2000/xmlns/";
  
      public DOMNodePointer(Node node, Locale locale){
          super(null, locale);
          this.node = node;
      }
  
      public DOMNodePointer(NodePointer parent, Node node){
          super(parent);
          this.node = node;
      }
  
      public boolean testNode(NodeTest test){
          return testNode(this, node, test);
      }
  
      public static boolean testNode(NodePointer pointer, Node node, NodeTest test){
          if (test == null){
              return true;
          }
          else if (test instanceof NodeNameTest){
              if (node.getNodeType() != Node.ELEMENT_NODE){
                  return false;
              }
  
              QName testName = ((NodeNameTest)test).getNodeName();
              String testLocalName = testName.getName();
              if (testLocalName.equals("*") || testLocalName.equals(DOMNodePointer.getLocalName(node))){
                  String testPrefix = testName.getPrefix();
                  String nodePrefix = DOMNodePointer.getPrefix(node);
                  if (equalStrings(testPrefix, nodePrefix)){
                      return true;
                  }
  
                  String testNS = pointer.getNamespaceURI(testPrefix);
                  String nodeNS = pointer.getNamespaceURI(nodePrefix);
                  return equalStrings(testNS, nodeNS);
              }
          }
          else if (test instanceof NodeTypeTest){
              int nodeType = node.getNodeType();
              switch (((NodeTypeTest)test).getNodeType()){
                  case Compiler.NODE_TYPE_NODE:
                      return nodeType == Node.ELEMENT_NODE;
                  case Compiler.NODE_TYPE_TEXT:
                      return nodeType == Node.CDATA_SECTION_NODE ||
                              nodeType == Node.TEXT_NODE;
                  case Compiler.NODE_TYPE_COMMENT:
                      return nodeType == Node.COMMENT_NODE;
                  case Compiler.NODE_TYPE_PI:
                      return nodeType == Node.PROCESSING_INSTRUCTION_NODE;
              }
              return false;
          }
          else if (test instanceof ProcessingInstructionTest){
              if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE){
                  String testPI = ((ProcessingInstructionTest)test).getTarget();
                  String nodePI = ((ProcessingInstruction)node).getTarget();
                  return testPI.equals(nodePI);
              }
          }
          return false;
      }
  
      private static boolean equalStrings(String s1, String s2){
          if (s1 == null && s2 != null){
              return false;
          }
          if (s1 != null && s2 == null){
              return false;
          }
  
          if (s1 != null && !s1.trim().equals(s2.trim())){
              return false;
          }
  
          return true;
      }
  
      public QName getName(){
          int type = node.getNodeType();
          if (type == Node.ELEMENT_NODE){
              return new QName(DOMNodePointer.getPrefix(node), DOMNodePointer.getLocalName(node));
          }
          else if (type == Node.PROCESSING_INSTRUCTION_NODE){
              return new QName(null, ((ProcessingInstruction)node).getTarget());
          }
          return null;
      }
  
      public String getNamespaceURI(){
          if (node.getNodeType() == Node.ELEMENT_NODE){
              return getNamespaceURI(getName().getPrefix());
          }
          return null;
      }
  
      public QName getExpandedName(){
          return new QName(getNamespaceURI(), getName().getName());
      }
  
      public NodeIterator childIterator(NodeTest test, boolean reverse, NodePointer startWith){
          return new DOMNodeIterator(this, test, reverse, startWith);
      }
  
      public NodeIterator attributeIterator(QName name){
          return new DOMAttributeIterator(this, name);
      }
  
      public NodePointer namespacePointer(String prefix){
          return new NamespacePointer(this, prefix);
      }
  
      public NodeIterator namespaceIterator(){
          return new DOMNamespaceIterator(this);
      }
  
      public String getNamespaceURI(String prefix){
          if (prefix == null || prefix.equals("")){
              return getDefaultNamespaceURI();
          }
  
          if (prefix.equals("xml")){
              return XML_NAMESPACE_URI;
          }
  
          if (prefix.equals("xmlns")){
              return XMLNS_NAMESPACE_URI;
          }
  
          String namespace = null;
          if (namespaces == null){
              namespaces = new HashMap();
          }
          else {
              namespace = (String)namespaces.get(prefix);
          }
  
          if (namespace == null){
              String qname = "xmlns:" + prefix;
              Node aNode = node;
              while (aNode != null){
                  if (aNode.getNodeType() == Node.ELEMENT_NODE){
                      Attr attr = ((Element)aNode).getAttributeNode(qname);
                      if (attr != null){
                          namespace = attr.getValue();
                          break;
                      }
                  }
                  aNode = aNode.getParentNode();
              }
              if (namespace == null || namespace.equals("")){
                  namespace = NodePointer.UNKNOWN_NAMESPACE;
              }
          }
  
          namespaces.put(prefix, namespace);
          // TBD: We are supposed to resolve relative URIs to absolute ones.
          return namespace;
      }
  
      public String getDefaultNamespaceURI(){
          if (defaultNamespace == null){
              Node aNode = node;
              while (aNode != null){
                  if (aNode.getNodeType() == Node.ELEMENT_NODE){
                      Attr attr = ((Element)aNode).getAttributeNode("xmlns");
                      if (attr != null){
                          defaultNamespace = attr.getValue();
                          break;
                      }
                  }
                  aNode = aNode.getParentNode();
              }
          }
          if (defaultNamespace == null){
              defaultNamespace = "";
          }
          // TBD: We are supposed to resolve relative URIs to absolute ones.
          return defaultNamespace.equals("") ? null : defaultNamespace;
      }
  
      public Object getBaseValue(){
          return node;
      }
  
      public Object getValue(){
          return node;
      }
  
      public boolean isActual(){
          return true;
      }
  
      public boolean isCollection(){
          return false;
      }
  
      public int getLength(){
          return 1;
      }
  
      public boolean isLeaf(){
          return !node.hasChildNodes();
      }
  
      /**
       * Returns true if the xml:lang attribute for the current node
       * or its parent has the specified prefix <i>lang</i>.
       * If no node has this prefix, calls <code>super.isLanguage(lang)</code>.
       */
      public boolean isLanguage(String lang){
          String current = getLanguage();
          if (current == null){
              return super.isLanguage(lang);
          }
          return current.toUpperCase().startsWith(lang.toUpperCase());
      }
  
      protected String getLanguage(){
          Node n = node;
          while (n != null){
              if (n.getNodeType() == Node.ELEMENT_NODE){
                  Element e = (Element)n;
                  String attr = e.getAttribute("xml:lang");
                  if (attr != null && !attr.equals("")){
                      return attr;
                  }
              }
              n = n.getParentNode();
          }
          return null;
      }
  
      /**
       * Sets text contents of the node to the specified value
       */
      public void setValue(Object value){
          String string = null;
          if (value != null){
              string = (String)TypeUtils.convert(value, String.class);
              if (string.equals("")){
                  string = null;
              }
          }
  
          if (node.getNodeType() == Node.TEXT_NODE){
              if (string != null){
                  node.setNodeValue(string);
              }
              else {
                  node.getParentNode().removeChild(node);
              }
          }
          else {
              NodeList children = node.getChildNodes();
              int count = children.getLength();
              for (int i = 0; i < count; i++){
                  Node child = children.item(i);
                  if (child.getNodeType() == Node.TEXT_NODE ||
                          child.getNodeType() == Node.CDATA_SECTION_NODE){
                      node.removeChild(child);
                  }
              }
              if (string != null){
                  Node text = node.getOwnerDocument().createTextNode(string);
                  node.appendChild(text);
              }
          }
      }
  
      public NodePointer createChild(JXPathContext context, QName name, int index){
          if (index == WHOLE_COLLECTION){
              index = 0;
          }
          if (!getAbstractFactory(context).createObject(context, this, node, name.toString(), index)){
              throw new RuntimeException("Factory could not create a child node for path: " +
                      asPath() + "/" + name + "[" + (index+1) + "]");
          }
          NodeIterator it = childIterator(new NodeNameTest(name), false, null);
          if (it == null || !it.setPosition(index + 1)){
              throw new RuntimeException("Factory could not create a child node for path: " +
                      asPath() + "/" + name + "[" + (index+1) + "]");
          }
          return it.getNodePointer();
      }
  
      public void createChild(JXPathContext context, QName name, int index, Object value){
          createChild(context, name, index).setValue(value);
      }
  
      public String asPath(){
          StringBuffer buffer = new StringBuffer();
          if (parent != null){
              buffer.append(parent.asPath());
          }
          switch(node.getNodeType()){
              case Node.ELEMENT_NODE:
                  // If the parent pointer is not a DOMNodePointer, it is
                  // the parent's responsibility to produce the node test part
                  // of the path
                  if (parent instanceof DOMNodePointer){
                      buffer.append('/');
                      buffer.append(getName());
                      buffer.append('[').append(getRelativePositionByName()).append(']');
                  }
                  break;
              case Node.TEXT_NODE:
              case Node.CDATA_SECTION_NODE:
                  buffer.append("/text()");
                  buffer.append('[').append(getRelativePositionOfTextNode()).append(']');
                  break;
              case Node.PROCESSING_INSTRUCTION_NODE:
                  String target = ((ProcessingInstruction)node).getTarget();
                  buffer.append("/processing-instruction(\'").append(target).append("')");
                  buffer.append('[').append(getRelativePositionOfPI(target)).append(']');
                  break;
              case Node.DOCUMENT_NODE:
                  // That'll be empty
          }
          return buffer.toString();
      }
  
      private int getRelativePositionByName(){
          int count = 1;
          Node n = node.getPreviousSibling();
          while (n != null){
              if (n.getNodeType() == Node.ELEMENT_NODE){
                  String nm = n.getNodeName();
                  if (nm.equals(node.getNodeName())){
                      count ++;
                  }
              }
              n = n.getPreviousSibling();
          }
          return count;
      }
  
      private int getRelativePositionOfTextNode(){
          int count = 1;
          Node n = node.getPreviousSibling();
          while (n != null){
              if (n.getNodeType() == Node.TEXT_NODE || n.getNodeType() == Node.CDATA_SECTION_NODE){
                  count ++;
              }
              n = n.getPreviousSibling();
          }
          return count;
      }
  
      private int getRelativePositionOfPI(String target){
          int count = 1;
          Node n = node.getPreviousSibling();
          while (n != null){
              if (n.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE &&
                      ((ProcessingInstruction)n).getTarget().equals(target)){
                  count ++;
              }
              n = n.getPreviousSibling();
          }
          return count;
      }
  
      public int hashCode(){
          return System.identityHashCode(node);
      }
  
      public boolean equals(Object object){
          if (object == this){
              return true;
          }
  
          if (!(object instanceof DOMNodePointer)){
              return false;
          }
  
          DOMNodePointer other = (DOMNodePointer)object;
          return node == other.node;
      }
  
      public static String getPrefix(Node node){
          String prefix = node.getPrefix();
          if (prefix != null){
              return prefix;
          }
  
          String name = node.getNodeName();
          int index = name.lastIndexOf(':');
          if (index == -1){
              return null;
          }
  
          return name.substring(0, index);
      }
  
      public static String getLocalName(Node node){
          String localName = node.getLocalName();
          if (localName != null){
              return localName;
          }
  
          String name = node.getNodeName();
          int index = name.lastIndexOf(':');
          if (index == -1){
              return name;
          }
  
          return name.substring(index + 1);
      }
  
      public Object getCanonicalValue(){
          return stringValue(node);
      }
  
      private String stringValue(Node node){
          int nodeType = node.getNodeType();
          if (nodeType == Node.COMMENT_NODE){
              String text = ((Comment)node).getData();
              return text == null ? "" : text.trim();
          }
          else if (nodeType == Node.TEXT_NODE ||
                  nodeType == Node.CDATA_SECTION_NODE){
              String text = node.getNodeValue();
              return text == null ? "" : text.trim();
          }
          else if (nodeType == Node.PROCESSING_INSTRUCTION_NODE){
              String text = ((ProcessingInstruction)node).getData();
              return text == null ? "" : text.trim();
          }
          else {
              NodeList list = node.getChildNodes();
              StringBuffer buf = new StringBuffer(16);
              for(int i = 0; i < list.getLength();i++) {
                  Node child = list.item(i);
                  if (child.getNodeType() == Node.TEXT_NODE){
                      buf.append(child.getNodeValue());
                  }
                  else {
                      buf.append(stringValue(child));
                  }
              }
              return buf.toString().trim();
          }
      }
  
      private AbstractFactory getAbstractFactory(JXPathContext context){
          AbstractFactory factory = context.getFactory();
          if (factory == null){
              throw new RuntimeException("Factory is not set on the JXPathContext - cannot create path: " + asPath());
          }
          return factory;
      }
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/dom/DOMPointerFactory.java
  
  Index: DOMPointerFactory.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/dom/DOMPointerFactory.java,v 1.1 2002/04/21 21:52:33 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:33 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model.dom;
  
  import org.apache.commons.jxpath.ri.QName;
  import org.apache.commons.jxpath.ri.model.NodePointer;
  import org.apache.commons.jxpath.ri.model.NodePointerFactory;
  
  import java.util.*;
  import org.w3c.dom.Node;
  
  /**
   * Implements NodePointerFactory for DOM elements.
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:33 $
   */
  public class DOMPointerFactory implements NodePointerFactory {
  
      public static final int DOM_POINTER_FACTORY_ORDER = 100;
  
      public int getOrder(){
          return DOM_POINTER_FACTORY_ORDER;
      }
  
      public NodePointer createNodePointer(QName name, Object bean, Locale locale){
          if (bean instanceof Node){
              return new DOMNodePointer((Node)bean, locale);
          }
          return null;
      }
  
      public NodePointer createNodePointer(NodePointer parent, QName name, Object bean){
          if (bean instanceof Node){
              return new DOMNodePointer(parent, (Node)bean);
          }
          return null;
      }
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/dom/NamespacePointer.java
  
  Index: NamespacePointer.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/dom/NamespacePointer.java,v 1.1 2002/04/21 21:52:33 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:33 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model.dom;
  
  import org.apache.commons.jxpath.ri.*;
  import org.apache.commons.jxpath.ri.Compiler;
  import org.apache.commons.jxpath.ri.compiler.*;
  import org.apache.commons.jxpath.ri.model.NodePointer;
  
  import java.util.*;
  
  /**
   * Represents a namespace node.
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:33 $
   */
  public class NamespacePointer extends NodePointer {
      private String prefix;
      private String namespaceURI;
  
      public NamespacePointer(NodePointer parent, String prefix){
          super(parent);
          this.prefix = prefix;
      }
  
      public NamespacePointer(NodePointer parent, String prefix, String namespaceURI){
          super(parent);
          this.prefix = prefix;
          this.namespaceURI = namespaceURI;
      }
  
      public QName getName(){
          return new QName(getNamespaceURI(), prefix);
      }
  
      public Object getBaseValue(){
          return null;
      }
  
      public Object getValue(){
          return getNamespaceURI();
      }
  
      public String getNamespaceURI(){
          if (namespaceURI == null){
              namespaceURI = parent.getNamespaceURI(prefix);
          }
          return namespaceURI;
      }
  
      public boolean isLeaf(){
          return true;
      }
  
      /**
       * Throws UnsupportedOperationException.
       */
      public void setValue(Object value){
          throw new UnsupportedOperationException("Cannot modify DOM trees");
      }
  
      public boolean testNode(NodeTest nodeTest){
          return nodeTest == null ||
                  ((nodeTest instanceof NodeTypeTest) &&
                      ((NodeTypeTest)nodeTest).getNodeType() == Compiler.NODE_TYPE_NODE);
      }
  
      public String asPath(){
          StringBuffer buffer = new StringBuffer();
          if (parent != null){
              buffer.append(parent.asPath());
              buffer.append('/');
          }
          buffer.append("namespace::");
          buffer.append(prefix);
          return buffer.toString();
      }
  
      public int hashCode(){
          String nsURI = getNamespaceURI();
          if (nsURI == null){
              return 0;
          }
          else {
              return nsURI.hashCode();
          }
      }
  
      public boolean equals(Object object){
          if (object == this){
              return true;
          }
  
          if (!(object instanceof NamespacePointer)){
              return false;
          }
  
          NamespacePointer other = (NamespacePointer)object;
          String nsURI = getNamespaceURI();
          String otherNSURI = other.getNamespaceURI();
          return (nsURI == null && otherNSURI == null) ||
                 (nsURI != null && nsURI.endsWith(otherNSURI));
      }
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/dom/package.html
  
  Index: package.html
  ===================================================================
  <body>
  Implementation of "model" APIs for W3C DOM.
  </body>
  
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/util/TypeUtils.java
  
  Index: TypeUtils.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/util/TypeUtils.java,v 1.1 2002/04/21 21:52:34 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:34 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.util;
  
  import java.util.*;
  import java.lang.reflect.*;
  import org.apache.commons.jxpath.*;
  
  /**
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:34 $
   */
  public class TypeUtils {
  
      private static final int NO_MATCH = 0;
      private static final int APPROXIMATE_MATCH = 1;
      private static final int EXACT_MATCH = 2;
      private static final Object[] EMPTY_ARRAY = new Object[0];
  
      public static Constructor lookupConstructor(Class targetClass, Object[] parameters){
          boolean tryExact = true;
          int count = parameters.length;
          Class types[] = new Class[count];
          for (int i = 0; i < count; i++){
              Object param = parameters[i];
              if (param != null){
                  types[i] = param.getClass();
              }
              else {
                  types[i] = null;
                  tryExact = false;
              }
          }
  
          Constructor constructor = null;
  
          if (tryExact){
              // First - without type conversion
              try {
                  constructor = targetClass.getConstructor(types);
                  if (constructor != null){
                      return constructor;
                  }
              }
              catch (NoSuchMethodException ex){
              }
          }
  
          int currentMatch = 0;
          boolean ambiguous = false;
  
          // Then - with type conversion
          Constructor[] constructors = targetClass.getConstructors();
          for (int i = 0; i < constructors.length; i++){
              int match = TypeUtils.matchParameterTypes(constructors[i].getParameterTypes(), parameters);
              if (match != TypeUtils.NO_MATCH){
                  if (match > currentMatch){
                      constructor = constructors[i];
                      currentMatch = match;
                      ambiguous = false;
                  }
                  else if (match == currentMatch){
                      ambiguous = true;
                  }
              }
          }
          if (ambiguous){
              throw new RuntimeException("Ambigous constructor " + Arrays.asList(parameters));
          }
          return constructor;
      }
  
      public static Method lookupStaticMethod(Class targetClass, String name, Object[] parameters){
          boolean tryExact = true;
          int count = parameters.length;
          Class types[] = new Class[count];
          for (int i = 0; i < count; i++){
              Object param = parameters[i];
              if (param != null){
                  types[i] = param.getClass();
              }
              else {
                  types[i] = null;
                  tryExact = false;
              }
          }
  
          Method method = null;
  
          if (tryExact){
              // First - without type conversion
              try {
                  method = targetClass.getMethod(name, types);
                  if (method != null && Modifier.isStatic(method.getModifiers())){
                      return method;
                  }
              }
              catch (NoSuchMethodException ex){
              }
          }
  
          int currentMatch = 0;
          boolean ambiguous = false;
  
          // Then - with type conversion
          Method[] methods = targetClass.getMethods();
          for (int i = 0; i < methods.length; i++){
              if (Modifier.isStatic(methods[i].getModifiers()) &&
                      methods[i].getName().equals(name)){
                  int match = TypeUtils.matchParameterTypes(methods[i].getParameterTypes(), parameters);
                  if (match != TypeUtils.NO_MATCH){
                      if (match > currentMatch){
                          method = methods[i];
                          currentMatch = match;
                          ambiguous = false;
                      }
                      else if (match == currentMatch){
                          ambiguous = true;
                      }
                  }
              }
          }
          if (ambiguous){
              throw new RuntimeException("Ambigous method call: " + name);
          }
          return method;
      }
  
      public static Method lookupMethod(Class targetClass, String name, Object[] parameters){
          if (parameters.length < 1 || parameters[0] == null){
              return null;
          }
  
          if (TypeUtils.matchType(targetClass, parameters[0]) == TypeUtils.NO_MATCH){
              return null;
          }
  
          targetClass = convert(parameters[0], targetClass).getClass();
  
          boolean tryExact = true;
          int count = parameters.length - 1;
          Class types[] = new Class[count];
          Object arguments[] = new Object[count];
          for (int i = 0; i < count; i++){
              Object param = parameters[i+1];
              arguments[i] = param;
              if (param != null){
                  types[i] = param.getClass();
              }
              else {
                  types[i] = null;
                  tryExact = false;
              }
          }
  
          Method method = null;
  
          if (tryExact){
              // First - without type conversion
              try {
                  method = targetClass.getMethod(name, types);
                  if (method != null && !Modifier.isStatic(method.getModifiers())){
                      return method;
                  }
              }
              catch (NoSuchMethodException ex){
              }
          }
  
          int currentMatch = 0;
          boolean ambiguous = false;
  
          // Then - with type conversion
          Method[] methods = targetClass.getMethods();
          for (int i = 0; i < methods.length; i++){
              if (!Modifier.isStatic(methods[i].getModifiers()) &&
                      methods[i].getName().equals(name)){
                  int match = TypeUtils.matchParameterTypes(methods[i].getParameterTypes(), arguments);
                  if (match != TypeUtils.NO_MATCH){
                      if (match > currentMatch){
                          method = methods[i];
                          currentMatch = match;
                          ambiguous = false;
                      }
                      else if (match == currentMatch){
                          ambiguous = true;
                      }
                  }
              }
          }
          if (ambiguous){
              throw new RuntimeException("Ambigous method call: " + name);
          }
          return method;
      }
  
      public static int matchParameterTypes(Class types[], Object parameters[]){
          int pi = 0;
          if (types.length >= 1 && ExpressionContext.class.isAssignableFrom(types[0])){
              pi++;
          }
          if (types.length != parameters.length + pi){
              return NO_MATCH;
          }
          int totalMatch = EXACT_MATCH;
          for (int i = 0; i < parameters.length; i++){
              int match = matchType(types[i + pi], parameters[i]);
              if (match == NO_MATCH){
                  return NO_MATCH;
              }
              if (match < totalMatch){
                  totalMatch = match;
              }
          }
          return totalMatch;
      }
  
      public static int matchType(Class expected, Object object){
          if (object == null){
              return APPROXIMATE_MATCH;
          }
  
          Class actual = object.getClass();
  
          if (expected.equals(actual)){
              return EXACT_MATCH;
          }
          if (expected.isAssignableFrom(actual)){
              return EXACT_MATCH;
          }
  
          if (canConvert(object, expected)){
              return APPROXIMATE_MATCH;
          }
  
          return NO_MATCH;
      }
  
      public static boolean canConvert(Object object, Class toType){
          if (object == null){
              return true;
          }
  
          if (toType == Object.class){
              return true;
          }
  
          Class fromType = object.getClass();
          if (fromType.equals(toType)){
              return true;
          }
  
          if (toType.isAssignableFrom(fromType)){
              return true;
          }
  
          if (toType == String.class){
              return true;
          }
  
          if (object instanceof Boolean){
              if (toType == boolean.class ||
                      Number.class.isAssignableFrom(toType)){
                  return true;
              }
          }
          else if (object instanceof Number){
              if (toType.isPrimitive() ||
                      Number.class.isAssignableFrom(toType)){
                  return true;
              }
          }
          else if (object instanceof Character){
              if (toType == char.class){
                  return true;
              }
          }
          else if (object instanceof String){
              if (toType.isPrimitive()){
                  return true;
              }
          }
          else if (object instanceof ExpressionContext){
              if (Collection.class.isAssignableFrom(toType)){
                  return true;
              }
              Pointer pointer = ((ExpressionContext)object).getContextNodePointer();
              if (pointer != null){
                  Object value = pointer.getValue();
                  return canConvert(value, toType);
              }
          }
          else if (fromType.isArray()){
              if (Array.getLength(object) == 1){
                  Object value = Array.get(object, 0);
                  return canConvert(value, toType);
              }
          }
          else if (object instanceof List){
              if (((List)object).size() == 1){
                  Object value = ((List)object).get(0);
                  return canConvert(value, toType);
              }
          }
          else if (object instanceof Collection){
              if (!((Collection)object).isEmpty()){
                  Iterator it = ((Collection)object).iterator();
                  Object value = it.next();
                  return canConvert(value, toType);
              }
          }
  
          // TBD: date conversion to/from string
          return false;
      }
  
      public static Object convert(Object object, Class toType){
          if (object == null){
              return null;
          }
  
          if (toType == Object.class){
              return object;
          }
  
          if (object instanceof ExpressionContext){
              if (Collection.class.isAssignableFrom(toType)){
                  List list = ((ExpressionContext)object).getContextNodeList();
                  Collection result = new ArrayList();
                  if (toType == List.class || toType == ArrayList.class){
                      result = new ArrayList();
                  }
                  else if (toType == Vector.class){
                      result = new Vector();
                  }
                  else if (toType == Set.class || toType == HashSet.class){
                      result = new HashSet();
                  }
                  int count = list.size();
                  for (int i = 0; i < count; i++){
                      Pointer ptr = (Pointer)list.get(i);
                      result.add(ptr.getValue());
                  }
                  return result;
              }
              else {
                  Object value = ((ExpressionContext)object).getContextNodePointer().getValue();
                  return convert(value, toType);
              }
          }
  
          Class fromType = object.getClass();
          if (fromType.equals(toType) || toType.isAssignableFrom(fromType)){
              return object;
          }
  
          if (toType == String.class){
              return object.toString();
          }
  
          if (object instanceof Boolean){
              if (toType == boolean.class){
                  return object;
              }
              boolean value = ((Boolean)object).booleanValue();
              return allocateNumber(toType, value ? 1 : 0);
          }
          else if (object instanceof Number){
              double value = ((Number)object).doubleValue();
              if (toType == boolean.class || toType == Boolean.class){
                  return value == 0.0 ? Boolean.FALSE : Boolean.TRUE;
              }
              if (toType.isPrimitive() ||
                      Number.class.isAssignableFrom(toType)){
                  return allocateNumber(toType, value);
              }
          }
          else if (object instanceof Character){
              if (toType == char.class){
                  return object;
              }
          }
          else if (object instanceof String){
              if (toType == boolean.class || toType == Boolean.class){
                  return new Boolean((String)object);
              }
              if (toType == char.class || toType == Character.class){
                  return new Character(((String)object).charAt(0));
              }
              if (toType == byte.class || toType == Byte.class){
                  return new Byte((String)object);
              }
              if (toType == short.class || toType == Short.class){
                  return new Short((String)object);
              }
              if (toType == int.class || toType == Integer.class){
                  return new Integer((String)object);
              }
              if (toType == long.class || toType == Long.class){
                  return new Long((String)object);
              }
              if (toType == float.class || toType == Float.class){
                  return new Float((String)object);
              }
              if (toType == double.class || toType == Double.class){
                  return new Double((String)object);
              }
          }
          else if (fromType.isArray()){
              Object value = Array.get(object, 0);
              return convert(value, toType);
          }
          else if (object instanceof List){
              Object value = ((List)object).get(0);
              return convert(value, toType);
          }
          else if (object instanceof Collection){
              Iterator it = ((Collection)object).iterator();
              Object value = it.next();
              return convert(value, toType);
          }
          return object;
      }
  
      private static Number allocateNumber(Class type, double value){
          if (type == Byte.class || type == byte.class){
              return new Byte((byte)value);
          }
          if (type == Short.class || type == short.class){
              return new Short((short)value);
          }
          if (type == Integer.class || type == int.class){
              return new Integer((int)value);
          }
          if (type == Long.class || type == long.class){
              return new Long((long)value);
          }
          if (type == Float.class || type == float.class){
              return new Float((float)value);
          }
          if (type == Double.class || type == double.class){
              return new Double(value);
          }
          return null;
      }
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/util/ValueUtils.java
  
  Index: ValueUtils.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/util/ValueUtils.java,v 1.1 2002/04/21 21:52:34 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/04/21 21:52:34 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2001 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 and was
   * originally based on software copyright (c) 2001, Plotnix, Inc,
   * <http://www.plotnix.com/>.
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.util;
  
  import org.apache.commons.jxpath.*;
  import org.apache.commons.jxpath.ri.Compiler;
  import org.apache.commons.jxpath.ri.compiler.*;
  import org.apache.commons.jxpath.functions.*;
  
  import java.lang.reflect.*;
  import java.util.*;
  import java.beans.*;
  
  /**
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/04/21 21:52:34 $
   */
  public class ValueUtils {
      private static Map dynamicPropertyHandlerMap = new HashMap();
  
      public static boolean isCollection(PropertyDescriptor propertyDescriptor){
          return false;
      }
  
      public static boolean isCollection(PropertyDescriptor propertyDescriptor, Object value){
          return isCollection(value);
      }
  
      public static boolean isCollection(Object value){
          if (value == null){
              return false;
          }
          else if (value.getClass().isArray()){
              return true;
          }
          else if (value instanceof Collection){
              return true;
          }
          return false;
      }
  
      public static int getLength(Object bean, PropertyDescriptor propertyDescriptor){
          Object obj = getValue(bean, propertyDescriptor);
          return getLength(obj);
      }
  
      public static int getLength(Object collection){
          if (collection == null){
              return 0;
          }
          else if (collection.getClass().isArray()){
              return Array.getLength(collection);
          }
          else if (collection instanceof Collection){
              return ((Collection)collection).size();
          }
          else {
              return 1;
          }
      }
  
      public static Object expandCollection(Object collection, int size){
          if (collection == null){
              return null;
          }
          else if (collection.getClass().isArray()){
              Object bigger = Array.newInstance(collection.getClass().getComponentType(), size);
              System.arraycopy(collection, 0, bigger, 0, Array.getLength(collection));
              return bigger;
          }
          else if (collection instanceof Collection){
              while (((Collection)collection).size() < size){
                  ((Collection)collection).add(null);
              }
              return collection;
          }
          else {
              throw new RuntimeException("Cannot turn " + collection.getClass().getName() +
                      " into a collection of size " + size);
          }
      }
  
      public static Object getValue(Object bean, PropertyDescriptor propertyDescriptor, int index){
          if (propertyDescriptor instanceof IndexedPropertyDescriptor){
              Object value;
              try {
                  IndexedPropertyDescriptor ipd = (IndexedPropertyDescriptor)propertyDescriptor;
                  Method method = ipd.getIndexedReadMethod();
                  if (method != null){
                      return method.invoke(bean, new Object[]{new Integer(index)});
                  }
              }
              catch (Exception ex){
                  throw new RuntimeException("Cannot access property: " + propertyDescriptor.getName() +
                      ", " + ex.getMessage());
              }
          }
          // We will fall through if there is no indexed read
  
          return getValue(getValue(bean, propertyDescriptor), index);
      }
  
      public static void setValue(Object bean, PropertyDescriptor propertyDescriptor, int index, Object value){
          if (propertyDescriptor instanceof IndexedPropertyDescriptor){
              try {
                  IndexedPropertyDescriptor ipd = (IndexedPropertyDescriptor)propertyDescriptor;
                  Method method = ipd.getIndexedWriteMethod();
                  if (method != null){
                      method.invoke(bean,
                          new Object[]{new Integer(index),
                                       convert(value, ipd.getIndexedPropertyType())});
                      return;
                  }
              }
              catch (Exception ex){
                  throw new RuntimeException("Cannot access property: " + propertyDescriptor.getName() +
                      ", " + ex.getMessage());
              }
          }
          // We will fall through if there is no indexed read
          setValue(getValue(bean, propertyDescriptor), index, value);
      }
  
      public static Object getValue(Object collection, int index){
          Object value = collection;
          if (collection != null){
              if (collection.getClass().isArray()){
                  if (index < 0 || index >= Array.getLength(collection)){
                      return null;
                  }
                  value = Array.get(collection, index);
              }
              else if (collection instanceof List){
                  if (index < 0 || index >= ((List)collection).size()){
                      return null;
                  }
                  value = ((List)collection).get(index);
              }
              else if (collection instanceof Collection){
                  int i = 0;
                  Iterator it = ((Collection)collection).iterator();
                  for (; i < index; i++){
                      it.next();
                  }
                  if (it.hasNext()){
                      value = it.next();
                  }
                  else {
                      value = null;
                  }
              }
          }
          return value;
      }
  
      public static void setValue(Object collection, int index, Object value){
          if (collection != null){
              if (collection.getClass().isArray()){
                  Array.set(collection, index, convert(value, collection.getClass().getComponentType()));
              }
              else if (collection instanceof List){
                  ((List)collection).set(index, value);
              }
              else if (collection instanceof Collection){
                  throw new UnsupportedOperationException("Cannot set value of an element of a " +
                          collection.getClass().getName());
              }
          }
      }
  
      public static Object getValue(Object bean, PropertyDescriptor propertyDescriptor){
          Object value;
          try {
              Method method = getAccessibleMethod(propertyDescriptor.getReadMethod());
              if (method == null){
                  throw new RuntimeException("No read method");
              }
              value = method.invoke(bean, new Object[0]);
          }
          catch (Exception ex){
              ex.printStackTrace();
              throw new RuntimeException("Cannot access property: " + propertyDescriptor.getName() +
                  ", " + ex.getMessage());
          }
          return value;
      }
  
      public static void setValue(Object bean, PropertyDescriptor propertyDescriptor, Object value){
          try {
              Method method = getAccessibleMethod(propertyDescriptor.getWriteMethod());
              if (method == null){
                  throw new RuntimeException("No write method");
              }
              value = convert(value, propertyDescriptor.getPropertyType());
              value = method.invoke(bean, new Object[]{value});
          }
          catch (Exception ex){
              throw new RuntimeException("Cannot modify property: " + propertyDescriptor.getName() +
                  ", " + ex);
          }
      }
  
      private static Object convert(Object value, Class type){
          if (!TypeUtils.canConvert(value, type)){
              throw new RuntimeException("Cannot convert value of class " +
                      (value == null ? "null" : value.getClass().getName()) +
                      " to type " + type);
          }
          return TypeUtils.convert(value, type);
      }
  
      /**
       * Returns a shared instance of the dynamic property handler class
       * returned by <code>getDynamicPropertyHandlerClass()</code>.
       */
      public static DynamicPropertyHandler getDynamicPropertyHandler(Class clazz) {
          DynamicPropertyHandler handler = (DynamicPropertyHandler)dynamicPropertyHandlerMap.get(clazz);
          if (handler == null){
              try {
                  handler = (DynamicPropertyHandler)clazz.newInstance();
              }
              catch (Exception ex){
                  throw new RuntimeException("Cannot allocate dynamic property handler " +
                      " of class " + clazz + ".\n" + ex);
              }
              dynamicPropertyHandlerMap.put(clazz, handler);
          }
          return handler;
      }
  
      // -------------------------------------------------------- Private Methods
      //
      //  The rest of the code in this file was copied FROM
      //  org.apache.commons.beanutils.PropertyUtil. We don't want to introduce a dependency
      //  on BeanUtils yet - DP.
      //
  
      /**
       * Return an accessible method (that is, one that can be invoked via
       * reflection) that implements the specified Method.  If no such method
       * can be found, return <code>null</code>.
       *
       * @param method The method that we wish to call
       */
      private static Method getAccessibleMethod(Method method) {
  
          // Make sure we have a method to check
          if (method == null) {
              return (null);
          }
  
          // If the requested method is not public we cannot call it
          if (!Modifier.isPublic(method.getModifiers())) {
              return (null);
          }
  
          // If the declaring class is public, we are done
          Class clazz = method.getDeclaringClass();
          if (Modifier.isPublic(clazz.getModifiers())) {
              return (method);
          }
  
          // Check the implemented interfaces and subinterfaces
          String methodName = method.getName();
          Class[] parameterTypes = method.getParameterTypes();
          method =
              getAccessibleMethodFromInterfaceNest(clazz,
                                                   method.getName(),
                                                   method.getParameterTypes());
          return (method);
      }
  
  
      /**
       * Return an accessible method (that is, one that can be invoked via
       * reflection) that implements the specified method, by scanning through
       * all implemented interfaces and subinterfaces.  If no such Method
       * can be found, return <code>null</code>.
       *
       * @param clazz Parent class for the interfaces to be checked
       * @param methodName Method name of the method we wish to call
       * @param parameterTypes The parameter type signatures
       */
      private static Method getAccessibleMethodFromInterfaceNest
          (Class clazz, String methodName, Class parameterTypes[]) {
  
          Method method = null;
  
          // Check the implemented interfaces of the parent class
          Class interfaces[] = clazz.getInterfaces();
          for (int i = 0; i < interfaces.length; i++) {
  
              // Is this interface public?
              if (!Modifier.isPublic(interfaces[i].getModifiers()))
                  continue;
  
              // Does the method exist on this interface?
              try {
                  method = interfaces[i].getDeclaredMethod(methodName,
                                                           parameterTypes);
              } catch (NoSuchMethodException e) {
                  ;
              }
              if (method != null)
                  break;
  
              // Recursively check our parent interfaces
              method =
                  getAccessibleMethodFromInterfaceNest(interfaces[i],
                                                       methodName,
                                                       parameterTypes);
              if (method != null)
                  break;
  
          }
  
          // Return whatever we have found
          return (method);
      }
  }
  
  
  1.12      +135 -107  jakarta-commons/jxpath/src/test/org/apache/commons/jxpath/JXPathTestCase.java
  
  Index: JXPathTestCase.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/test/org/apache/commons/jxpath/JXPathTestCase.java,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- JXPathTestCase.java	11 Apr 2002 02:57:41 -0000	1.11
  +++ JXPathTestCase.java	21 Apr 2002 21:52:34 -0000	1.12
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/test/org/apache/commons/jxpath/JXPathTestCase.java,v 1.11 2002/04/11 02:57:41 dmitri Exp $
  - * $Revision: 1.11 $
  - * $Date: 2002/04/11 02:57:41 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/test/org/apache/commons/jxpath/JXPathTestCase.java,v 1.12 2002/04/21 21:52:34 dmitri Exp $
  + * $Revision: 1.12 $
  + * $Date: 2002/04/21 21:52:34 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -73,11 +73,17 @@
   
   import org.apache.commons.jxpath.ri.*;
   import org.apache.commons.jxpath.ri.parser.*;
  -import org.apache.commons.jxpath.ri.pointers.*;
  +import org.apache.commons.jxpath.ri.model.*;
  +import org.apache.commons.jxpath.ri.model.beans.*;
   import org.apache.commons.jxpath.ri.axes.*;
   import org.apache.commons.jxpath.ri.compiler.*;
  +import org.apache.commons.jxpath.ri.compiler.Expression;
   import java.beans.*;
   
  +import org.apache.xpath.XPath;
  +import org.apache.xpath.XPathContext;
  +import org.apache.xml.utils.PrefixResolver;
  +import org.apache.xml.utils.PrefixResolverDefault;
   
   /**
    * <p>
  @@ -89,11 +95,11 @@
    * <p>
    *   Note that the tests are dependant upon the static aspects
    *   (such as array sizes...) of the TestBean.java class, so ensure
  - *   than all changes to TestBean are reflected here.
  + *   that all changes to TestBean are reflected here.
    * </p>
    *
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.11 $ $Date: 2002/04/11 02:57:41 $
  + * @version $Revision: 1.12 $ $Date: 2002/04/21 21:52:34 $
    */
   
   public class JXPathTestCase extends TestCase
  @@ -163,7 +169,7 @@
        * Test property iterators, the core of the graph traversal engine
        */
       public void testIndividualIterators(){
  -        if (enabled){
  +        if (true){
   //        testIndividual(0, 0, true, false, 3);
               testIndividual(+1, 0, true, false, 0);
               testIndividual(-1, 0, true, false, 4);
  @@ -181,17 +187,17 @@
       }
   
       private void testIndividual(int relativePropertyIndex, int offset, boolean useStartLocation, boolean reverse, int expected){
  -        PropertyOwnerPointer root = (PropertyOwnerPointer)NodePointer.createNodePointer(new QName(null, "root"), bean, Locale.getDefault());
  +        PropertyOwnerPointer root = (PropertyOwnerPointer)NodePointer.newNodePointer(new QName(null, "root"), bean, Locale.getDefault());
           NodeIterator it;
   
           if (useStartLocation){
               PropertyPointer holder = root.getPropertyPointer();
               holder.setPropertyIndex(relativeProperty(holder, relativePropertyIndex));
               holder.setIndex(offset);
  -            it = holder.siblingIterator(new NodeNameTest(new QName(null, "integers")), reverse);
  +            it = root.childIterator(new NodeNameTest(new QName(null, "integers")), reverse, holder);
           }
           else {
  -            it = root.childIterator(new NodeNameTest(new QName(null, "integers")), reverse);
  +            it = root.childIterator(new NodeNameTest(new QName(null, "integers")), reverse, null);
           }
   
           int size = 0;
  @@ -204,7 +210,7 @@
       }
   
       public void testMultipleIterators(){
  -        if (enabled){
  +        if (true){
               testMultiple(0, 0, true, false, 20);
   
               testMultiple(3, 0, true, false, 16);
  @@ -219,17 +225,17 @@
       }
   
       private void testMultiple(int propertyIndex, int offset, boolean useStartLocation, boolean reverse, int expected){
  -        PropertyOwnerPointer root = (PropertyOwnerPointer)NodePointer.createNodePointer(new QName(null, "root"), bean, Locale.getDefault());
  +        PropertyOwnerPointer root = (PropertyOwnerPointer)NodePointer.newNodePointer(new QName(null, "root"), bean, Locale.getDefault());
           NodeIterator it;
   
           if (useStartLocation){
               PropertyPointer holder = root.getPropertyPointer();
               holder.setPropertyIndex(propertyIndex);
               holder.setIndex(offset);
  -            it = holder.siblingIterator(null, reverse);
  +            it = root.childIterator(null, reverse, holder);
           }
           else {
  -            it = root.childIterator(null, reverse);
  +            it = root.childIterator(null, reverse, null);
           }
   
           int size = 0;
  @@ -256,34 +262,35 @@
        * Test JXPath.getValue() with various arguments
        */
       public void testGetValue(){
  -        if (enabled){
  -            JXPathContext context = JXPathContext.newContext(bean);
  -            testGetValue(context, "2+2",                     new Double(4.0));
  -            testGetValue(context, "boolean",                 Boolean.FALSE);
  -            testGetValue(context, "substring(boolean, 1,2)", "fa"); // 'fa'lse
  -            testGetValue(context, "int*2",                   new Double(2.0));
  -            testGetValue(context, "integers[1]",             new Integer(1));
  -            testGetValue(context, "nestedBean",              bean.getNestedBean());
  -            testGetValue(context, "nestedBean/boolean",      Boolean.FALSE);
  -            testGetValue(context, "object/name",             "Name 5");
  -            testGetValue(context, "objects[1]",              new Integer(1));
  -            testGetValue(context, "map/Key1",                "Value 1");
  -            testGetValue(context, "beans[name = 'Name 1']",  bean.getBeans()[0]);
  -            testGetValue(context, ".[1]/int",                new Integer(1));
  +        if (!enabled){
  +            return;
  +        }
  +        JXPathContext context = JXPathContext.newContext(bean);
  +        testGetValue(context, "2+2",                     new Double(4.0));
  +        testGetValue(context, "boolean",                 Boolean.FALSE);
  +        testGetValue(context, "substring(boolean, 1,2)", "fa"); // 'fa'lse
  +        testGetValue(context, "int*2",                   new Double(2.0));
  +        testGetValue(context, "integers[1]",             new Integer(1));
  +        testGetValue(context, "nestedBean",              bean.getNestedBean());
  +        testGetValue(context, "nestedBean/boolean",      Boolean.FALSE);
  +        testGetValue(context, "object/name",             "Name 5");
  +        testGetValue(context, "objects[1]",              new Integer(1));
  +        testGetValue(context, "map/Key1",                "Value 1");
  +        testGetValue(context, "beans[name = 'Name 1']",  bean.getBeans()[0]);
  +        testGetValue(context, ".[1]/int",                new Integer(1));
   //        testGetValue(context, "id('foo')",               new Integer(1));
   //        testGetValue(context, "key('foo', 'bar')",               new Integer(1));
  -            testGetValue(context, "integers[1]",            new Double(1), Double.class);
  -            testGetValue(context, "2 + 3",                  "5.0", String.class);
  -            testGetValue(context, "2 + 3",                  Boolean.TRUE, boolean.class);
  -            boolean exception = false;
  -            try {
  -                testGetValue(context, "'foo'",                  null, Date.class);
  -            }
  -            catch(Exception ex){
  -                exception = true;
  -            }
  -            assertTrue("Type conversion exception", exception);
  +        testGetValue(context, "integers[1]",            new Double(1), Double.class);
  +        testGetValue(context, "2 + 3",                  "5.0", String.class);
  +        testGetValue(context, "2 + 3",                  Boolean.TRUE, boolean.class);
  +        boolean exception = false;
  +        try {
  +            testGetValue(context, "'foo'",                  null, Date.class);
           }
  +        catch(Exception ex){
  +            exception = true;
  +        }
  +        assertTrue("Type conversion exception", exception);
       }
   
       /**
  @@ -419,72 +426,89 @@
        * Test JXPath.createPath() with various arguments
        */
       public void testCreatePath(){
  -        if (enabled){
  -            TestBean tBean = new TestBean();
  -            tBean.setNestedBean(null);
  -            tBean.setBeans(null);
  -            tBean.setMap(null);
  -            JXPathContext context = JXPathContext.newContext(tBean);
  -            context.setFactory(new TestFactory());
  +//        if (!enabled){
  +//            return;
  +//        }
  +        TestBean tBean = createTestBeanWithDOM();
  +        tBean.setNestedBean(null);
  +        tBean.setBeans(null);
  +        tBean.setMap(null);
  +        JXPathContext context = JXPathContext.newContext(tBean);
  +        context.setFactory(new TestFactory());
   
  -            // Calls factory.declareVariable("string")
  -            testCreatePath(context, "$string", "Value");
  +        // Calls factory.declareVariable("string")
  +        testCreatePath(context, "$string", "Value");
   
  -            // Calls factory.declareVariable("stringArray"). The factory needs to create a collection
  -            testCreatePath(context, "$stringArray[2]", "Value2");
  -            assertEquals("Created <" + "$stringArray[1]" + ">", "Value1", context.getValue("$stringArray[1]"));
  +        // Calls factory.declareVariable("stringArray"). The factory needs to create a collection
  +        testCreatePath(context, "$stringArray[2]", "Value2");
  +        assertEquals("Created <" + "$stringArray[1]" + ">", "Value1", context.getValue("$stringArray[1]"));
   
  -            context.getVariables().declareVariable("array", new String[]{"Value1"});
  +        context.getVariables().declareVariable("array", new String[]{"Value1"});
   
  -            // Does not involve factory at all - just expands the collection
  -            testCreatePath(context, "$array[2]", "Value2");
  -            assertEquals("Created <" + "$array[1]" + ">", "Value1", context.getValue("$array[1]"));
  +        // Does not involve factory at all - just expands the collection
  +        testCreatePath(context, "$array[2]", "Value2");
   
  -            // Calls factory.declareVariable("test"). The factory should create a TestBean
  -            testCreatePath(context, "$test/boolean", Boolean.TRUE);
  +        // Make sure it is still the same array
  +        assertEquals("Created <" + "$array[1]" + ">", "Value1", context.getValue("$array[1]"));
   
  -            // Calls factory.declareVariable("testArray").
  -            // The factory should create a collection of TestBeans.
  -            // Then calls factory.createObject(..., collection, "testArray", 1).
  -            // That one should produce an instance of TestBean and put it in the collection
  -            // at index 1.
  -            testCreatePath(context, "$testArray[2]/boolean", Boolean.TRUE);
  +        // Calls factory.declareVariable("test"). The factory should create a TestBean
  +        testCreatePath(context, "$test/boolean", Boolean.TRUE);
   
  -            // Calls factory.createObject(..., TestBean, "nestedBean")
  -            testCreatePath(context, "nestedBean/int", new Integer(1));
  +        // Calls factory.declareVariable("testArray").
  +        // The factory should create a collection of TestBeans.
  +        // Then calls factory.createObject(..., collection, "testArray", 1).
  +        // That one should produce an instance of TestBean and put it in the collection
  +        // at index 1.
  +        testCreatePath(context, "$testArray[2]/boolean", Boolean.TRUE);
   
  -            // Calls factory.expandCollection(..., testBean, "beans", 2), then
  -            // factory.createObject(..., testBean, "beans", 2)
  -            testCreatePath(context, "beans[2]/int", new Integer(2));
  +        // Calls factory.createObject(..., TestBean, "nestedBean")
  +        testCreatePath(context, "nestedBean/int", new Integer(1));
   
  -            // Another, but the collection already exists
  -            testCreatePath(context, "beans[3]/int", new Integer(3));
  +        // Calls factory.expandCollection(..., testBean, "beans", 2), then
  +        // factory.createObject(..., testBean, "beans", 2)
  +        testCreatePath(context, "beans[2]/int", new Integer(2));
   
  -            // Calls factory.expandCollection(..., testBean, "beans", 2), then
  -            // sets the value
  -            testCreatePath(context, "nestedBean/strings[2]", "Test");
  +        // Another, but the collection already exists
  +        testCreatePath(context, "beans[3]/int", new Integer(3));
   
  -            // Calls factory.createObject(..., testBean, "map"), then
  -            // sets the value
  -            testCreatePath(context, "map[@name = 'TestKey1']", "Test");
  +        // Calls factory.expandCollection(..., testBean, "beans", 2), then
  +        // sets the value
  +        testCreatePath(context, "nestedBean/strings[2]", "Test");
   
  -            // Calls factory.createObject(..., testBean, "map"), then
  -            // then factory.createObject(..., map, "TestKey2"), then
  -            // sets the value
  -            testCreatePath(context, "map[@name = 'TestKey2']/int", new Integer(4));
  +        // Calls factory.createObject(..., testBean, "map"), then
  +        // sets the value
  +        testCreatePath(context, "map[@name = 'TestKey1']", "Test");
   
  -            // Calls factory.expandCollection(..., map, "TestKey3", 2), then
  -            testCreatePath(context, "map/TestKey3[2]", "Test");
  +        // Calls factory.createObject(..., testBean, "map"), then
  +        // then factory.createObject(..., map, "TestKey2"), then
  +        // sets the value
  +        testCreatePath(context, "map[@name = 'TestKey2']/int", new Integer(4));
   
  -            // Should be the same as the one before
  -            testCreatePath(context, "map[@name='TestKey3'][3]", "Test");
  +        // Calls factory.expandCollection(..., map, "TestKey3", 2)
  +        testCreatePath(context, "map/TestKey3[2]", "Test");
   
  -            // Comprehensive tests: map & bean
  -            tBean.setMap(null);
  -            testCreatePath(context, "map[@name = 'TestKey5']/nestedBean/int", new Integer(5));
  -            tBean.setMap(null);
  -            testCreatePath(context, "map[@name = 'TestKey5']/beans[2]/int", new Integer(6));
  -        }
  +        // Should be the same as the one before
  +        testCreatePath(context, "map[@name='TestKey3'][3]", "Test");
  +
  +        // Create an element of a dynamic map element, which is a collection
  +        testCreatePath(context, "map/TestKey4[1]/int", new Integer(5));
  +
  +        tBean.getMap().remove("TestKey4");
  +
  +        // Should be the same as the one before
  +        testCreatePath(context, "map[@name = 'TestKey4'][1]/int", new Integer(5));
  +
  +        // Create a DOM element
  +        testCreatePath(context, "vendor/location[3]", "");
  +
  +        // Create a DOM element with contents
  +        testCreatePath(context, "vendor/location[3]/address/street", "Lemon Circle");
  +
  +        // Comprehensive tests: map & bean
  +        tBean.setMap(null);
  +        testCreatePath(context, "map[@name = 'TestKey5']/nestedBean/int", new Integer(6));
  +        tBean.setMap(null);
  +        testCreatePath(context, "map[@name = 'TestKey5']/beans[2]/int", new Integer(7));
       }
   
       private void testCreatePath(JXPathContext context, String path, Object value){
  @@ -493,15 +517,16 @@
       }
   
       public void testNull(){
  -        if (enabled){
  -            JXPathContext context = JXPathContext.newContext(new TestNull());
  -            testGetValue(context, "nothing", null);
  -            testGetValue(context, "child/nothing", null);
  -            testGetValue(context, "array[2]", null);
  -            context.setLenient(true);
  -            testGetValue(context, "nothing/something", null);
  -            testGetValue(context, "array[2]/something", null);
  +        if (!enabled){
  +            return;
           }
  +        JXPathContext context = JXPathContext.newContext(new TestNull());
  +        testGetValue(context, "nothing", null);
  +        testGetValue(context, "child/nothing", null);
  +        testGetValue(context, "array[2]", null);
  +        context.setLenient(true);
  +        testGetValue(context, "nothing/something", null);
  +        testGetValue(context, "array[2]/something", null);
       }
   
       /**
  @@ -526,7 +551,7 @@
           }
   
           public Pointer getContextNodePointer(){
  -            return NodePointer.createNodePointer(null, object, Locale.getDefault());
  +            return NodePointer.newNodePointer(null, object, Locale.getDefault());
           }
   
           public List getContextNodeList(){
  @@ -703,6 +728,7 @@
       }
   
       static final XP[] xpath_tests = new XP[]{
  +
           // Numbers
           test("1", new Double(1.0)),
           testEval("1", list(new Double(1.0))),
  @@ -741,7 +767,6 @@
           // Traversal
           // ancestor::
           test("int/ancestor::root = /", Boolean.TRUE),
  -//        testEval("beans/name/ancestor-or-self::node()", new Double(5)),
           test("count(beans/name/ancestor-or-self::node())", new Double(5)),
           test("beans/name/ancestor-or-self::node()[3] = /", Boolean.TRUE),
   
  @@ -756,6 +781,7 @@
           test("nestedBean/name", "Name 0"),
           testPath("nestedBean/name", "/nestedBean/name"),
           testEvalPath("nestedBean/name", list("/nestedBean/name")),
  +
           testEval("integers", list(new Integer(1), new Integer(2), new Integer(3), new Integer(4))),
           testPath("integers", "/integers"),
           testEvalPath("integers", list("/integers[1]", "/integers[2]", "/integers[3]", "/integers[4]")),
  @@ -767,6 +793,8 @@
           testEval("beans[1]/strings", list("String 1", "String 2", "String 3")),
           testEval("beans/strings[2]", list("String 2", "String 2")),
           test("beans/strings[2]", "String 2"),
  +
  +        test("beans/strings[name(.)='strings'][2]", "String 2"),
           test("(beans/strings[2])[1]", "String 2"),
           test("count(*)", new Double(21)),
           test("count(child::node())", new Double(21)),
  @@ -829,14 +857,14 @@
           test("count((integers | beans[1]/strings)[name(.) = 'strings'])", new Double(3)),
   
           // Note that the following is different from "integer[2]" - it is a filter expression
  -        test("(integers)[2]", new Integer(2)),
  +        test("(integers)[2]", new Integer(2)),        // TBD
   
           // Core functions
           test("integers[last()]", new Integer(4)),
           test("integers[position() = last() - 1]", new Integer(3)),
           testEval("integers[position() < 3]", list(new Integer(1), new Integer(2))),
           test("count(beans/strings)", new Double(6)),
  -//        test("integers[string() = '2.0']", new Integer(2)),  // Incorrect -- TBD
  +        test("integers[string() = '2.0']", new Integer(2)),
   
           test("name(integers)", "integers"),
           testEval("*[name(.) = 'integers']", list(new Integer(1), new Integer(2), new Integer(3), new Integer(4))),
  @@ -926,7 +954,11 @@
           test("/beans[contains(test:path(), '[2]')]/name", "Name 2"),
   
           // null
  +        testPath("$null", "$null"),
  +        testPath("$null[3]", "$null[3]"),
           testPath("$testnull/nothing", "$testnull/nothing"),
  +        testPath("$testnull/nothing[2]", "$testnull/nothing[2]"),
  +        testPath("beans[8]/int", "/beans[8]/int"),
           testEval("$testnull/nothing[1]", Collections.EMPTY_LIST),
       };
   
  @@ -1102,9 +1134,5 @@
           testPath("$test/object/vendor/location[1]//street", "$test/object/vendor[1]/location[1]/address[1]/street[1]"),
           test("$object//street", "Orchard Road"),
           testPath("$object//street", "$object/vendor[1]/location[1]/address[1]/street[1]"),
  -
  -        testPath("$null", "$null"),
  -//        testPath("$null[3]", "$null[3]"),
       };
  -}
  -
  +}
  \ No newline at end of file
  
  
  
  1.2       +7 -3      jakarta-commons/jxpath/src/test/org/apache/commons/jxpath/TestBeanWithDOM.java
  
  Index: TestBeanWithDOM.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/test/org/apache/commons/jxpath/TestBeanWithDOM.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- TestBeanWithDOM.java	3 Sep 2001 01:22:31 -0000	1.1
  +++ TestBeanWithDOM.java	21 Apr 2002 21:52:34 -0000	1.2
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/test/org/apache/commons/jxpath/TestBeanWithDOM.java,v 1.1 2001/09/03 01:22:31 dmitri Exp $
  - * $Revision: 1.1 $
  - * $Date: 2001/09/03 01:22:31 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/test/org/apache/commons/jxpath/TestBeanWithDOM.java,v 1.2 2002/04/21 21:52:34 dmitri Exp $
  + * $Revision: 1.2 $
  + * $Date: 2002/04/21 21:52:34 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -69,7 +69,7 @@
    * General purpose test bean for JUnit tests for the "jxpath" component.
    *
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.1 $ $Date: 2001/09/03 01:22:31 $
  + * @version $Revision: 1.2 $ $Date: 2002/04/21 21:52:34 $
    */
   public class TestBeanWithDOM extends TestBean {
       private Node node;
  @@ -77,6 +77,10 @@
   
       public Node getVendor(){
           return node;
  +    }
  +
  +    public Node[] getVendors(){
  +        return new Node[]{node};
       }
   
       public void setVendor(Node node){
  
  
  
  1.2       +50 -17    jakarta-commons/jxpath/src/test/org/apache/commons/jxpath/TestFactory.java
  
  Index: TestFactory.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jxpath/src/test/org/apache/commons/jxpath/TestFactory.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- TestFactory.java	10 Apr 2002 03:40:21 -0000	1.1
  +++ TestFactory.java	21 Apr 2002 21:52:34 -0000	1.2
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/jxpath/src/test/org/apache/commons/jxpath/TestFactory.java,v 1.1 2002/04/10 03:40:21 dmitri Exp $
  - * $Revision: 1.1 $
  - * $Date: 2002/04/10 03:40:21 $
  + * $Header: /home/cvs/jakarta-commons/jxpath/src/test/org/apache/commons/jxpath/TestFactory.java,v 1.2 2002/04/21 21:52:34 dmitri Exp $
  + * $Revision: 1.2 $
  + * $Date: 2002/04/21 21:52:34 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
  @@ -63,12 +63,13 @@
   package org.apache.commons.jxpath;
   
   import java.util.*;
  +import org.w3c.dom.*;
   
   /**
    * Test AbstractFactory.
    *
    * @author Dmitri Plotnikov
  - * @version $Revision: 1.1 $ $Date: 2002/04/10 03:40:21 $
  + * @version $Revision: 1.2 $ $Date: 2002/04/21 21:52:34 $
    */
   public class TestFactory extends AbstractFactory {
   
  @@ -82,11 +83,21 @@
               ((TestBean[])parent)[index] = new TestBean();
               return true;
           }
  +        else if (name.equals("strings")){
  +            NestedTestBean bean = (NestedTestBean)parent;
  +            bean.setStrings(new String[index + 1]);
  +            bean.getStrings()[index] = "";
  +            return true;
  +        }
           else if (name.equals("nestedBean")){
               ((TestBean)parent).setNestedBean(new NestedTestBean("newName"));
               return true;
           }
           else if (name.equals("beans")){
  +            TestBean bean = (TestBean)parent;
  +            if (bean.getBeans() == null || index >= bean.getBeans().length){
  +                bean.setBeans(new NestedTestBean[index + 1]);
  +            }
               ((TestBean)parent).getBeans()[index] = new NestedTestBean("newName");
               return true;
           }
  @@ -102,6 +113,10 @@
               ((Map)parent).put(name, new Vector());
               return true;
           }
  +        else if (name.equals("TestKey4")){
  +            ((Map)parent).put(name, new Object[]{new TestBean()});
  +            return true;
  +        }
           else if (name.equals("TestKey5")){
               TestBean tb = new TestBean();
               tb.setNestedBean(null);
  @@ -109,9 +124,41 @@
               ((Map)parent).put(name, tb);
               return true;
           }
  +        else if (name.equals("location") || name.equals("address") || name.equals("street")){
  +            addElement((Node)parent, index, name);
  +            return true;
  +        }
           return false;
       }
   
  +    private void addElement(Node parent, int index, String tag){
  +        boolean repeat = true;
  +        while(repeat){
  +            Node child = parent.getFirstChild();
  +            int count = 0;
  +            while (child != null){
  +                if (child.getNodeName().equals(tag)){
  +                    if (count == index){
  +                        repeat = false;
  +                        break;
  +                    }
  +                    count++;
  +                }
  +                child = child.getNextSibling();
  +            }
  +            if (child != null){
  +                child = child.getNextSibling();
  +            }
  +            Node newElement = parent.getOwnerDocument().createElement(tag);
  +            if (child != null){
  +                parent.insertBefore(newElement, child);
  +            }
  +            else {
  +                parent.appendChild(newElement);
  +            }
  +        }
  +    }
  +
       /**
        * Create a new object and set it on the specified variable
        */
  @@ -130,19 +177,5 @@
           }
           context.getVariables().declareVariable(name, null);
           return true;
  -    }
  -
  -    public boolean expandCollection(JXPathContext context, Pointer pointer, Object parent, String name, int size){
  -        if (name.equals("beans")){
  -            TestBean bean = (TestBean)parent;
  -            bean.setBeans(new NestedTestBean[size]);
  -            return true;
  -        }
  -        else if (name.equals("strings")){
  -            NestedTestBean bean = (NestedTestBean)parent;
  -            bean.setStrings(new String[size]);
  -            return true;
  -        }
  -        return false;
       }
   }
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>