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/11/28 02:01:30 UTC

cvs commit: jakarta-commons/jxpath/src/test/org/apache/commons/jxpath/ri/model/dynamic DynamicPropertiesModelTest.java

dmitri      2002/11/27 17:01:30

  Added:       jxpath/src/java/org/apache/commons/jxpath/ri/model/dynamic
                        DynamicPropertyPointer.java
                        DynamicPropertyIterator.java
                        DynamicPointerFactory.java DynamicPointer.java
                        DynamicAttributeIterator.java
               jxpath/src/test/org/apache/commons/jxpath/ri/model/dynamic
                        DynamicPropertiesModelTest.java
  Removed:     jxpath/src/java/org/apache/commons/jxpath/ri/model/beans
                        DynamicPropertyPointer.java
                        DynamicPointerFactory.java DynamicPointer.java
               jxpath/src/test/org/apache/commons/jxpath/ri/model/beans
                        DynamicPropertiesModelTest.java
  Log:
  Encapsulated dynamic properties into a package of their own
  
  Revision  Changes    Path
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/dynamic/DynamicPropertyPointer.java
  
  Index: DynamicPropertyPointer.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/dynamic/DynamicPropertyPointer.java,v 1.1 2002/11/28 01:01:30 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/11/28 01:01:30 $
   *
   * ====================================================================
   * 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.dynamic;
  
  import java.util.Arrays;
  
  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.beans.PropertyPointer;
  import org.apache.commons.jxpath.util.ValueUtils;
  
  /**
   * Pointer pointing to a property of an object with dynamic properties.
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/11/28 01:01:30 $
   */
  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 isContainer(){
          return true;
      }
  
      /**
       * 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;
          }
      }
  
      /**
       * 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 getImmediateNode(){
          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 NodePointer createPath(JXPathContext context, Object value){
          return createChild(context, getName(), index, value);
      }
  
      public NodePointer 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 JXPathException(
                          "Factory could not create an object for path: "
                              + asPath());
                  }
                  collection = getBaseValue();
              }
  
              if (index < 0) {
                  throw new JXPathException("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);
          }
          NodePointer ptr = (NodePointer) clone();
          ptr.setIndex(index);
          return ptr;
      }
  
      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 JXPathException(
                      "Factory could not create an object for path: " + asPath());
              }
              collection = getBaseValue();
          }
  
          if (index < 0) {
              throw new JXPathException("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 (getNode() == null) {
              AbstractFactory factory = getAbstractFactory(context);
              int inx = (index == WHOLE_COLLECTION ? 0 : index);
              if (!factory
                  .createObject(
                      context,
                      this,
                      getBean(),
                      getPropertyName(),
                      inx)) {
                  throw new JXPathException(
                      "Factory could not create an object for path: " + asPath());
              }
          }
          return this;
      }
  
      public void remove(){
          if (index == WHOLE_COLLECTION) {
              handler.setProperty(getBean(), getPropertyName(), null);
          }
          else if (isCollection()) {
              Object collection = ValueUtils.remove(getBaseValue(), index);
              handler.setProperty(getBean(), getPropertyName(), collection);
          }
          else if (index == 0) {
              handler.setProperty(getBean(), getPropertyName(), null);
          }
      }
  
      public String asPath(){
          StringBuffer buffer = new StringBuffer();
          buffer.append(getParent().asPath());
          if (buffer.length() == 0) {
              buffer.append("/.");
          }
          else if (buffer.charAt(buffer.length() - 1) == '/') {
              buffer.append('.');
          }
          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 JXPathException("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/dynamic/DynamicPropertyIterator.java
  
  Index: DynamicPropertyIterator.java
  ===================================================================
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Commons", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model.dynamic;
  
  import org.apache.commons.jxpath.ri.model.NodePointer;
  import org.apache.commons.jxpath.ri.model.beans.PropertyIterator;
  import org.apache.commons.jxpath.ri.model.beans.PropertyOwnerPointer;
  
  /**
   * <code>DynamicPropertyIterator</code> is different from a regular
   * <code>PropertyIterator</code> in that given a property name it
   * will always find that property (albeit with a null value).
   * 
   * @author <a href="mailto:dmitri@apache.org">Dmitri Plotnikov</a>
   * @version $Id: DynamicPropertyIterator.java,v 1.1 2002/11/28 01:01:30 dmitri Exp $
   */
  public class DynamicPropertyIterator extends PropertyIterator {
  
      public DynamicPropertyIterator(
              PropertyOwnerPointer pointer,
              String name,
              boolean reverse,
              NodePointer startWith) 
      {
          super(pointer, name, reverse, startWith);
      }
  
      protected void prepareForIndividualProperty(String name){
          ((DynamicPropertyPointer)getPropertyPointer()).setPropertyName(name);
          super.prepareForIndividualProperty(name);
     }
  }
  
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/dynamic/DynamicPointerFactory.java
  
  Index: DynamicPointerFactory.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/dynamic/DynamicPointerFactory.java,v 1.1 2002/11/28 01:01:30 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/11/28 01:01:30 $
   *
   * ====================================================================
   * 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.dynamic;
  
  import java.util.Locale;
  
  import org.apache.commons.jxpath.DynamicPropertyHandler;
  import org.apache.commons.jxpath.JXPathBeanInfo;
  import org.apache.commons.jxpath.JXPathIntrospector;
  import org.apache.commons.jxpath.ri.QName;
  import org.apache.commons.jxpath.ri.model.NodePointer;
  import org.apache.commons.jxpath.ri.model.NodePointerFactory;
  import org.apache.commons.jxpath.ri.model.beans.NullPointer;
  import org.apache.commons.jxpath.util.ValueUtils;
  
  /**
   * Implements NodePointerFactory for Dynamic classes like Map.
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/11/28 01:01:30 $
   */
  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 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/dynamic/DynamicPointer.java
  
  Index: DynamicPointer.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/dynamic/DynamicPointer.java,v 1.1 2002/11/28 01:01:30 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/11/28 01:01:30 $
   *
   * ====================================================================
   * 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.dynamic;
  
  import java.util.Locale;
  
  import org.apache.commons.jxpath.DynamicPropertyHandler;
  import org.apache.commons.jxpath.JXPathIntrospector;
  import org.apache.commons.jxpath.ri.QName;
  import org.apache.commons.jxpath.ri.model.NodeIterator;
  import org.apache.commons.jxpath.ri.model.NodePointer;
  import org.apache.commons.jxpath.ri.model.beans.PropertyOwnerPointer;
  import org.apache.commons.jxpath.ri.model.beans.PropertyPointer;
  
  /**
   * 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/11/28 01:01:30 $
   */
  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 NodeIterator createNodeIterator(
                  String property, boolean reverse, NodePointer startWith)
      {
          return new DynamicPropertyIterator(this, property, reverse, startWith);
      }
  
      public NodeIterator attributeIterator(QName name){
          return new DynamicAttributeIterator(this, name);
      }
  
      public QName getName(){
          return name;
      }
  
      /**
       * Returns the DP object iself.
       */
      public Object getBaseValue(){
          return bean;
      }
      
      public boolean isLeaf() {
          Object value = getNode();
          return value == null
              || JXPathIntrospector.getBeanInfo(value.getClass()).isAtomic();
      }    
      
      public boolean isCollection(){
          return false;
      }
  
      /**
       * Returns 1.
       */
      public int getLength(){
          return 1;
      }
  
      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);
      }
  }
  
  
  1.1                  jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/model/dynamic/DynamicAttributeIterator.java
  
  Index: DynamicAttributeIterator.java
  ===================================================================
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Commons", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jxpath.ri.model.dynamic;
  
  import org.apache.commons.jxpath.ri.QName;
  import org.apache.commons.jxpath.ri.model.beans.BeanAttributeIterator;
  import org.apache.commons.jxpath.ri.model.beans.PropertyOwnerPointer;
  
  /**
   * <code>DynamicAttributeIterator</code> is different from a regular
   * <code>BeanAttributeIterator</code> in that given a property name it
   * will always find that property (albeit with a null value).
   *  
   * @author <a href="mailto:dmitri@apache.org">Dmitri Plotnikov</a>
   * @version $Id: DynamicAttributeIterator.java,v 1.1 2002/11/28 01:01:30 dmitri Exp $
   */
  public class DynamicAttributeIterator extends BeanAttributeIterator {
  
      public DynamicAttributeIterator(PropertyOwnerPointer parent, QName name) {
          super(parent, name);
      }
  
       protected void prepareForIndividualProperty(String name){
           ((DynamicPropertyPointer)getPropertyPointer()).setPropertyName(name);
           super.prepareForIndividualProperty(name);
      }
  }
  
  
  
  1.1                  jakarta-commons/jxpath/src/test/org/apache/commons/jxpath/ri/model/dynamic/DynamicPropertiesModelTest.java
  
  Index: DynamicPropertiesModelTest.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/jxpath/src/test/org/apache/commons/jxpath/ri/model/dynamic/DynamicPropertiesModelTest.java,v 1.1 2002/11/28 01:01:30 dmitri Exp $
   * $Revision: 1.1 $
   * $Date: 2002/11/28 01:01:30 $
   *
   * ====================================================================
   * 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.dynamic;
  
  import org.apache.commons.jxpath.JXPathContext;
  import org.apache.commons.jxpath.JXPathTestCase;
  import org.apache.commons.jxpath.TestBean;
  
  /**
   * @todo more iterator testing with maps
   *
   * @author Dmitri Plotnikov
   * @version $Revision: 1.1 $ $Date: 2002/11/28 01:01:30 $
   */
  
  public class DynamicPropertiesModelTest extends JXPathTestCase
  {
      private static boolean enabled = true;
      private JXPathContext context;
  
      /**
       * Construct a new instance of this test case.
       *
       * @param name Name of the test case
       */
      public DynamicPropertiesModelTest(String name){
          super(name);
      }
  
      public void setUp(){
          if (context == null){
              context = JXPathContext.newContext(new TestBean());
              context.setFactory(new TestDynamicPropertyFactory());
          }
      }
  
      public void testAxisChild(){
          assertXPathValue(context,
                  "map/Key1",
                  "Value 1");
  
          assertXPathPointer(context,
                  "map/Key1",
                  "/map[@name='Key1']");
  
          assertXPathValue(context,
                  "map/Key2/name",
                  "Name 6");
  
          assertXPathPointer(context,
                  "map/Key2/name",
                  "/map[@name='Key2']/name");
      }
  
      public void testAxisDescendant(){
          assertXPathValue(context,
                  "//Key1",
                  "Value 1");
      }
  
      /**
       * Testing the pseudo-attribute "name" that dynamic property
       * objects appear to have.
       */
      public void testAttributeName(){
          assertXPathValue(context,
                  "map[@name = 'Key1']",
                  "Value 1");
  
          assertXPathPointer(context,
                  "map[@name = 'Key1']",
                  "/map[@name='Key1']");
  
          assertXPathPointerLenient(context,
                  "map[@name = 'Key&quot;&apos;&quot;&apos;1']",
                  "/map[@name='Key&quot;&apos;&quot;&apos;1']");
  
          assertXPathValue(context,
                  "/.[@name='map']/Key2/name",
                  "Name 6");
  
          assertXPathPointer(context,
                  "/.[@name='map']/Key2/name",
                  "/map[@name='Key2']/name");
  
          // Bean in a map
          assertXPathValue(context,
                  "/map[@name='Key2'][@name='name']",
                  "Name 6");
  
          assertXPathPointer(context,
                  "/map[@name='Key2'][@name='name']",
                  "/map[@name='Key2']/name");
  
          // Map in a bean in a map
          assertXPathValue(context,
                  "/.[@name='map'][@name='Key2'][@name='name']",
                  "Name 6");
  
          assertXPathPointer(context,
                  "/.[@name='map'][@name='Key2'][@name='name']",
                  "/map[@name='Key2']/name");
      }
      
      public void testSetPrimitiveValue(){
          assertXPathSetValue(context, 
                  "map/Key1",
                  new Integer(6));
      }
      
      public void testSetCollection(){
          // See if we can assign a whole collection        
          context.setValue(
                  "map/Key1", 
                  new Integer[]{new Integer(7), new Integer(8)});
          
          // And then an element in that collection
          assertXPathSetValue(context,
                  "map/Key1[1]", 
                  new Integer(9));
      }
      
      public void testSetNewKey(){
          assertXPathSetValue(context,
                  "map/Key4", 
                  new Integer(7));
      }
      
      public void testCreatePath(){
          TestBean bean = (TestBean)context.getContextBean();
          bean.setMap(null);
          
          // Calls factory.createObject(..., testBean, "map"), then
          // sets the value
          assertXPathCreatePath(context, 
                  "/map[@name='TestKey1']", 
                  "", 
                  "/map[@name='TestKey1']");
      }
      
      public void testCreatePathAndSetValue(){
          TestBean bean = (TestBean)context.getContextBean();
          bean.setMap(null);
          
          // Calls factory.createObject(..., testBean, "map"), then
          // sets the value
          assertXPathCreatePathAndSetValue(context, 
                  "/map[@name='TestKey1']", 
                  "Test", 
                  "/map[@name='TestKey1']");
      }
      
      public void testCreatePathCreateBean(){
          TestBean bean = (TestBean)context.getContextBean();
          bean.setMap(null);
          
          // Calls factory.createObject(..., testBean, "map"), then
          // then factory.createObject(..., map, "TestKey2"), then
          // sets the value
          assertXPathCreatePath(context, 
                  "/map[@name='TestKey2']/int", 
                  new Integer(1),
                  "/map[@name='TestKey2']/int");
      }
      
      public void testCreatePathAndSetValueCreateBean(){
          TestBean bean = (TestBean)context.getContextBean();
          bean.setMap(null);
          
          // Calls factory.createObject(..., testBean, "map"), then
          // then factory.createObject(..., map, "TestKey2"), then
          // sets the value
          assertXPathCreatePathAndSetValue(context, 
                  "/map[@name='TestKey2']/int", 
                  new Integer(4),
                  "/map[@name='TestKey2']/int");
      }
      
      public void testCreatePathCollectionElement(){
          TestBean bean = (TestBean)context.getContextBean();
          bean.setMap(null);
          
  
          assertXPathCreatePath(context, 
                  "/map/TestKey3[2]", 
                  null,
                  "/map[@name='TestKey3'][2]");
  
          // Should be the same as the one before
          assertXPathCreatePath(context, 
                  "/map[@name='TestKey3'][3]", 
                  null,
                  "/map[@name='TestKey3'][3]");
      }
      
      public void testCreatePathAndSetValueCollectionElement(){
          TestBean bean = (TestBean)context.getContextBean();
          bean.setMap(null);
          
  
          assertXPathCreatePathAndSetValue(context, 
                  "/map/TestKey3[2]", 
                  "Test1",
                  "/map[@name='TestKey3'][2]");
  
          // Should be the same as the one before
          assertXPathCreatePathAndSetValue(context, 
                  "/map[@name='TestKey3'][3]", 
                  "Test2",
                  "/map[@name='TestKey3'][3]");
      }
      
      public void testCreatePathNewCollectionElement(){
          TestBean bean = (TestBean)context.getContextBean();
          bean.setMap(null);
          
          // Create an element of a dynamic map element, which is a collection
          assertXPathCreatePath(context, 
                  "/map/TestKey4[1]/int", 
                  new Integer(1),
                  "/map[@name='TestKey4'][1]/int");
  
          bean.getMap().remove("TestKey4");
  
          // Should be the same as the one before
          assertXPathCreatePath(context, 
                  "/map/TestKey4[1]/int", 
                  new Integer(1),
                  "/map[@name='TestKey4'][1]/int");
      }
      
      public void testCreatePathAndSetValueNewCollectionElement(){
          TestBean bean = (TestBean)context.getContextBean();
          bean.setMap(null);
          
          // Create an element of a dynamic map element, which is a collection
          assertXPathCreatePathAndSetValue(context, 
                  "/map/TestKey4[1]/int", 
                  new Integer(2),
                  "/map[@name='TestKey4'][1]/int");
  
          bean.getMap().remove("TestKey4");
  
          // Should be the same as the one before
          assertXPathCreatePathAndSetValue(context, 
                  "/map/TestKey4[1]/int", 
                  new Integer(3),
                  "/map[@name='TestKey4'][1]/int");
      }
      
      public void testRemovePath(){
          TestBean bean = (TestBean)context.getContextBean();
          bean.getMap().put("TestKey1", "test");
  
          // Remove dynamic property
          context.removePath("map[@name = 'TestKey1']");
          assertEquals("Remove dynamic property value", null,
                      context.getValue("map[@name = 'TestKey1']"));
      }
      
      public void testRemovePathArrayElement(){
          TestBean bean = (TestBean)context.getContextBean();
  
          bean.getMap().put("TestKey2", new String[]{"temp1", "temp2"});
          context.removePath("map[@name = 'TestKey2'][1]");
          assertEquals("Remove dynamic property collection element", "temp2",
                      context.getValue("map[@name = 'TestKey2'][1]"));
      }
  }
  
  

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