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.container;
018    
019    import java.util.Locale;
020    
021    import org.apache.commons.jxpath.Container;
022    import org.apache.commons.jxpath.ri.QName;
023    import org.apache.commons.jxpath.ri.compiler.NodeTest;
024    import org.apache.commons.jxpath.ri.model.NodeIterator;
025    import org.apache.commons.jxpath.ri.model.NodePointer;
026    import org.apache.commons.jxpath.util.ValueUtils;
027    
028    /**
029     * Transparent pointer to a Container. The {@link #getValue()} method
030     * returns the contents of the container, rather than the container
031     * itself.
032     *
033     * @author Dmitri Plotnikov
034     * @version $Revision: 652884 $ $Date: 2008-05-02 15:02:00 -0500 (Fri, 02 May 2008) $
035     */
036    public class ContainerPointer extends NodePointer {
037        private Container container;
038        private NodePointer valuePointer;
039    
040        private static final long serialVersionUID = 6140752946621686118L;
041    
042        /**
043         * Create a new ContainerPointer.
044         * @param container Container object
045         * @param locale Locale
046         */
047        public ContainerPointer(Container container, Locale locale) {
048            super(null, locale);
049            this.container = container;
050        }
051    
052        /**
053         * Create a new ContainerPointer.
054         * @param parent parent pointer
055         * @param container Container object
056         */
057        public ContainerPointer(NodePointer parent, Container container) {
058            super(parent);
059            this.container = container;
060        }
061    
062        /**
063         * This type of node is auxiliary.
064         * @return <code>true</code>.
065         */
066        public boolean isContainer() {
067            return true;
068        }
069    
070        public QName getName() {
071            return null;
072        }
073    
074        public Object getBaseValue() {
075            return container;
076        }
077    
078        public boolean isCollection() {
079            Object value = getBaseValue();
080            return value != null && ValueUtils.isCollection(value);
081        }
082    
083        public int getLength() {
084            Object value = getBaseValue();
085            return value == null ? 1 : ValueUtils.getLength(value);
086        }
087    
088        public boolean isLeaf() {
089            return getValuePointer().isLeaf();
090        }
091    
092        public Object getImmediateNode() {
093            Object value = getBaseValue();
094            if (index != WHOLE_COLLECTION) {
095                return index >= 0 && index < getLength() ? ValueUtils.getValue(value, index) : null;
096            }
097            return ValueUtils.getValue(value);
098        }
099    
100        public void setValue(Object value) {
101            // TODO: what if this is a collection?
102            container.setValue(value);
103        }
104    
105        public NodePointer getImmediateValuePointer() {
106            if (valuePointer == null) {
107                Object value = getImmediateNode();
108                valuePointer = NodePointer.newChildNodePointer(this, getName(), value);
109            }
110            return valuePointer;
111        }
112    
113        public int hashCode() {
114            return System.identityHashCode(container) + index;
115        }
116    
117        public boolean equals(Object object) {
118            if (object == this) {
119                return true;
120            }
121    
122            if (!(object instanceof ContainerPointer)) {
123                return false;
124            }
125    
126            ContainerPointer other = (ContainerPointer) object;
127            return container == other.container && index == other.index;
128        }
129    
130        public NodeIterator childIterator(
131            NodeTest test,
132            boolean reverse,
133            NodePointer startWith) {
134            return getValuePointer().childIterator(test, reverse, startWith);
135        }
136    
137        public NodeIterator attributeIterator(QName name) {
138            return getValuePointer().attributeIterator(name);
139        }
140    
141        public NodeIterator namespaceIterator() {
142            return getValuePointer().namespaceIterator();
143        }
144    
145        public NodePointer namespacePointer(String namespace) {
146            return getValuePointer().namespacePointer(namespace);
147        }
148    
149        public boolean testNode(NodeTest nodeTest) {
150            return getValuePointer().testNode(nodeTest);
151        }
152    
153        public int compareChildNodePointers(
154            NodePointer pointer1,
155            NodePointer pointer2) {
156            return pointer1.getIndex() - pointer2.getIndex();
157        }
158    
159        public String getNamespaceURI(String prefix) {
160            return getValuePointer().getNamespaceURI(prefix);
161        }
162    
163        public String asPath() {
164            return parent == null ? "/" : parent.asPath();
165        }
166    }