    1   /*
    2    * Copyright 1999-2004 The Apache Software Foundation
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *     http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  package org.apache.commons.jxpath.ri.model.beans;
    17
    18  import java.util.Locale;
    19
    20  import org.apache.commons.jxpath.JXPathContext;
    21  import org.apache.commons.jxpath.JXPathIntrospector;
    22  import org.apache.commons.jxpath.ri.QName;
    23  import org.apache.commons.jxpath.ri.compiler.NodeTest;
    24  import org.apache.commons.jxpath.ri.model.NodeIterator;
    25  import org.apache.commons.jxpath.ri.model.NodePointer;
    26  import org.apache.commons.jxpath.util.ValueUtils;
    27
    28  /***
    29   * Transparent pointer to a collection (array or Collection).
    30   *
    31   * @author Dmitri Plotnikov
    32   * @version $Revision: 1.19 $ $Date: 2004/04/04 22:06:35 $
    33   */
    34  public class CollectionPointer extends NodePointer {
    35      private Object collection;
    36      private NodePointer valuePointer;
    37
    38      public CollectionPointer(Object collection, Locale locale) {
    39          super(null, locale);
    40          this.collection = collection;
    41      }
    42
    43      public CollectionPointer(NodePointer parent, Object collection) {
    44          super(parent);
    45          this.collection = collection;
    46      }
    47
    48      public QName getName() {
    49          return null;
    50      }
    51
    52      public Object getBaseValue() {
    53          return collection;
    54      }
    55
    56      public boolean isCollection() {
    57          return true;
    58      }
    59
    60      public int getLength() {
    61          return ValueUtils.getLength(getBaseValue());
    62      }
    63
    64      public boolean isLeaf() {
    65          Object value = getNode();
    66          return value == null
    67              || JXPathIntrospector.getBeanInfo(value.getClass()).isAtomic();
    68      }
    69
    70      public boolean isContainer() {
    71          return index != WHOLE_COLLECTION;
    72      }
    73
    74      public Object getImmediateNode() {
    75          if (index != WHOLE_COLLECTION) {
    76              return ValueUtils.getValue(collection, index);
    77          }
    78          else {
    79              return ValueUtils.getValue(collection);
    80          }
    81      }
    82
    83      public void setValue(Object value) {
    84          if (index == WHOLE_COLLECTION) {
    85              parent.setValue(value);
    86          }
    87          else {
    88              ValueUtils.setValue(collection, index, value);
    89          }
    90      }
    91
    92      public void setIndex(int index) {
    93          super.setIndex(index);
    94          valuePointer = null;
    95      }
    96
    97      public NodePointer getValuePointer() {
    98          if (valuePointer == null) {
    99              if (index == WHOLE_COLLECTION) {
    100                 valuePointer = this;
    101             }
    102             else {
    103                 Object value = getImmediateNode();
    104                 valuePointer =
    105                     NodePointer.newChildNodePointer(this, getName(), value);
    106             }
    107         }
    108         return valuePointer;
    109     }
    110
    111     public NodePointer createPath(JXPathContext context) {
    112         Object collection = getBaseValue();
    113         if (ValueUtils.getLength(collection) <= index) {
    114             collection = ValueUtils.expandCollection(getNode(), index + 1);
    115         }
    116         return this;
    117     }
    118
    119     public NodePointer createPath(JXPathContext context, Object value) {
    120         NodePointer ptr = createPath(context);
    121         ptr.setValue(value);
    122         return ptr;
    123     }
    124
    125     public NodePointer createChild(
    126         JXPathContext context,
    127         QName name,
    128         int index,
    129         Object value)
    130     {
    131         NodePointer ptr = (NodePointer) clone();
    132         ptr.setIndex(index);
    133         return ptr.createPath(context, value);
    134     }
    135
    136     public NodePointer createChild(
    137         JXPathContext context,
    138         QName name,
    139         int index)
    140     {
    141         NodePointer ptr = (NodePointer) clone();
    142         ptr.setIndex(index);
    143         return ptr.createPath(context);
    144     }
    145
    146     public int hashCode() {
    147         return System.identityHashCode(collection) + index;
    148     }
    149
    150     public boolean equals(Object object) {
    151         if (object == this) {
    152             return true;
    153         }
    154
    155         if (!(object instanceof CollectionPointer)) {
    156             return false;
    157         }
    158
    159         CollectionPointer other = (CollectionPointer) object;
    160         return collection == other.collection && index == other.index;
    161     }
    162
    163     public NodeIterator childIterator(NodeTest test,
    164                 boolean reverse, NodePointer startWith)
    165     {
    166         if (index == WHOLE_COLLECTION) {
    167             return new CollectionChildNodeIterator(
    168                 this,
    169                 test,
    170                 reverse,
    171                 startWith);
    172         }
    173         else {
    174             return getValuePointer().childIterator(test, reverse, startWith);
    175         }
    176     }
    177
    178     public NodeIterator attributeIterator(QName name) {
    179         if (index == WHOLE_COLLECTION) {
    180             return new CollectionAttributeNodeIterator(this, name);
    181         }
    182         return getValuePointer().attributeIterator(name);
    183     }
    184
    185     public NodeIterator namespaceIterator() {
    186         if (index == WHOLE_COLLECTION) {
    187             return null;
    188         }
    189         return getValuePointer().namespaceIterator();
    190     }
    191
    192     public NodePointer namespacePointer(String namespace) {
    193         if (index == WHOLE_COLLECTION) {
    194             return null;
    195         }
    196         return getValuePointer().namespacePointer(namespace);
    197     }
    198
    199     public boolean testNode(NodeTest nodeTest) {
    200 //        if (index
    201         /*** @todo: infinite loop here */
    202         return getValuePointer().testNode(nodeTest);
    203     }
    204
    205     public int compareChildNodePointers(
    206                 NodePointer pointer1, NodePointer pointer2)
    207     {
    208         return pointer1.getIndex() - pointer2.getIndex();
    209     }
    210
    211     /***
    212      * Returns an XPath that maps to this Pointer.
    213      */
    214     public String asPath() {
    215         StringBuffer buffer = new StringBuffer();
    216         NodePointer parent = getImmediateParentPointer();
    217         if (parent != null) {
    218             buffer.append(parent.asPath());
    219             if (index != WHOLE_COLLECTION) {
    220                 // Address the list[1][2] case
    221                 if (parent.getIndex() != WHOLE_COLLECTION) {
    222                     buffer.append("/.");
    223                 }
    224                 buffer.append("[").append(index + 1).append(']');
    225             }
    226         }
    227         else {
    228             if (index != WHOLE_COLLECTION) {
    229                 buffer.append("/.[").append(index + 1).append(']');
    230             }
    231             else {
    232                 buffer.append("/");
    233             }
    234         }
    235
    236         return buffer.toString();
    237     }
    238 }