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 */
017package org.apache.commons.jxpath.ri.model.container;
018
019import java.util.Locale;
020
021import org.apache.commons.jxpath.Container;
022import org.apache.commons.jxpath.ri.QName;
023import org.apache.commons.jxpath.ri.compiler.NodeTest;
024import org.apache.commons.jxpath.ri.model.NodeIterator;
025import org.apache.commons.jxpath.ri.model.NodePointer;
026import 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 22:02:00 +0200 (Fr, 02 Mai 2008) $
035 */
036public 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}