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