    001    /*
    002     * Licensed to the Apache Software Foundation (ASF) under one or more
    003     * contributor license agreements.  See the NOTICE file distributed with
    004     * this work for additional information regarding copyright ownership.
    005     * The ASF licenses this file to You under the Apache License, Version 2.0
    006     * (the "License"); you may not use this file except in compliance with
    007     * the License.  You may obtain a copy of the License at
    008     *
    009     *     http://www.apache.org/licenses/LICENSE-2.0
    010     *
    011     * Unless required by applicable law or agreed to in writing, software
    012     * distributed under the License is distributed on an "AS IS" BASIS,
    013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014     * See the License for the specific language governing permissions and
    015     * limitations under the License.
    016     */
    017    package org.apache.commons.jxpath.ri.model.beans;
    018
    019    import java.util.Locale;
    020
    021    import org.apache.commons.jxpath.JXPathContext;
    022    import org.apache.commons.jxpath.JXPathIntrospector;
    023    import org.apache.commons.jxpath.ri.Compiler;
    024    import org.apache.commons.jxpath.ri.QName;
    025    import org.apache.commons.jxpath.ri.compiler.NodeNameTest;
    026    import org.apache.commons.jxpath.ri.compiler.NodeTest;
    027    import org.apache.commons.jxpath.ri.compiler.NodeTypeTest;
    028    import org.apache.commons.jxpath.ri.model.NodeIterator;
    029    import org.apache.commons.jxpath.ri.model.NodePointer;
    030    import org.apache.commons.jxpath.util.ValueUtils;
    031
    032    /**
    033     * Transparent pointer to a collection (array or Collection).
    034     *
    035     * @author Dmitri Plotnikov
    036     * @version $Revision: 668329 $ $Date: 2008-06-16 16:59:48 -0500 (Mon, 16 Jun 2008) $
    037     */
    038    public class CollectionPointer extends NodePointer {
    039        private Object collection;
    040        private NodePointer valuePointer;
    041
    042        private static final long serialVersionUID = 8620254915563256588L;
    043
    044        /**
    045         * Create a new CollectionPointer.
    046         * @param collection value
    047         * @param locale Locale
    048         */
    049        public CollectionPointer(Object collection, Locale locale) {
    050            super(null, locale);
    051            this.collection = collection;
    052        }
    053
    054        /**
    055         * Create a new CollectionPointer.
    056         * @param parent parent NodePointer
    057         * @param collection value
    058         */
    059        public CollectionPointer(NodePointer parent, Object collection) {
    060            super(parent);
    061            this.collection = collection;
    062        }
    063
    064        public QName getName() {
    065            return null;
    066        }
    067
    068        public Object getBaseValue() {
    069            return collection;
    070        }
    071
    072        public boolean isCollection() {
    073            return true;
    074        }
    075
    076        public int getLength() {
    077            return ValueUtils.getLength(getBaseValue());
    078        }
    079
    080        public boolean isLeaf() {
    081            Object value = getNode();
    082            return value == null || JXPathIntrospector.getBeanInfo(value.getClass()).isAtomic();
    083        }
    084
    085        public boolean isContainer() {
    086            return index != WHOLE_COLLECTION;
    087        }
    088
    089        public Object getImmediateNode() {
    090            return index == WHOLE_COLLECTION ? ValueUtils.getValue(collection)
    091                    : ValueUtils.getValue(collection, index);
    092        }
    093
    094        public void setValue(Object value) {
    095            if (index == WHOLE_COLLECTION) {
    096                parent.setValue(value);
    097            }
    098            else {
    099                ValueUtils.setValue(collection, index, value);
    100            }
    101        }
    102
    103        public void setIndex(int index) {
    104            super.setIndex(index);
    105            valuePointer = null;
    106        }
    107
    108        public NodePointer getValuePointer() {
    109            if (valuePointer == null) {
    110                if (index == WHOLE_COLLECTION) {
    111                    valuePointer = this;
    112                }
    113                else {
    114                    Object value = getImmediateNode();
    115                    valuePointer =
    116                        NodePointer.newChildNodePointer(this, getName(), value);
    117                }
    118            }
    119            return valuePointer;
    120        }
    121
    122        public NodePointer createPath(JXPathContext context) {
    123            if (ValueUtils.getLength(getBaseValue()) <= index) {
    124                collection = ValueUtils.expandCollection(getNode(), index + 1);
    125            }
    126            return this;
    127        }
    128
    129        public NodePointer createPath(JXPathContext context, Object value) {
    130            NodePointer ptr = createPath(context);
    131            ptr.setValue(value);
    132            return ptr;
    133        }
    134
    135        public NodePointer createChild(
    136            JXPathContext context,
    137            QName name,
    138            int index,
    139            Object value) {
    140            NodePointer ptr = (NodePointer) clone();
    141            ptr.setIndex(index);
    142            return ptr.createPath(context, value);
    143        }
    144
    145        public NodePointer createChild(
    146            JXPathContext context,
    147            QName name,
    148            int index) {
    149            NodePointer ptr = (NodePointer) clone();
    150            ptr.setIndex(index);
    151            return ptr.createPath(context);
    152        }
    153
    154        public int hashCode() {
    155            return System.identityHashCode(collection) + index;
    156        }
    157
    158        public boolean equals(Object object) {
    159            if (object == this) {
    160                return true;
    161            }
    162
    163            if (!(object instanceof CollectionPointer)) {
    164                return false;
    165            }
    166
    167            CollectionPointer other = (CollectionPointer) object;
    168            return collection == other.collection && index == other.index;
    169        }
    170
    171        public NodeIterator childIterator(NodeTest test,
    172                    boolean reverse, NodePointer startWith) {
    173            if (index == WHOLE_COLLECTION) {
    174                return new CollectionChildNodeIterator(
    175                    this,
    176                    test,
    177                    reverse,
    178                    startWith);
    179            }
    180            return getValuePointer().childIterator(test, reverse, startWith);
    181        }
    182
    183        public NodeIterator attributeIterator(QName name) {
    184            return index == WHOLE_COLLECTION ? new CollectionAttributeNodeIterator(this, name)
    185                    : getValuePointer().attributeIterator(name);
    186        }
    187
    188        public NodeIterator namespaceIterator() {
    189            return index == WHOLE_COLLECTION ? null : getValuePointer().namespaceIterator();
    190        }
    191
    192        public NodePointer namespacePointer(String namespace) {
    193            return index == WHOLE_COLLECTION ? null : getValuePointer().namespacePointer(namespace);
    194        }
    195
    196        public boolean testNode(NodeTest test) {
    197            if (index == WHOLE_COLLECTION) {
    198                if (test == null) {
    199                    return true;
    200                }
    201                if (test instanceof NodeNameTest) {
    202                    return false;
    203                }
    204                return test instanceof NodeTypeTest && ((NodeTypeTest) test).getNodeType() == Compiler.NODE_TYPE_NODE;
    205            }
    206            return getValuePointer().testNode(test);
    207        }
    208
    209        public int compareChildNodePointers(
    210                    NodePointer pointer1, NodePointer pointer2) {
    211            return pointer1.getIndex() - pointer2.getIndex();
    212        }
    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            return buffer.toString();
    236        }
    237    }