    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.beans;
    019
    020import org.apache.commons.jxpath.JXPathContext;
    021import org.apache.commons.jxpath.ri.QName;
    022import org.apache.commons.jxpath.ri.model.NodePointer;
    023
    024/**
    025 * Used when there is a need to construct a Pointer for a collection element that does not exist. For example, if the path is "foo[3]", but the collection "foo"
    026 * only has one element or is empty or is null, the NullElementPointer can be used to capture this situation without putting a regular NodePointer into an
    027 * invalid state. Just create a NullElementPointer with index 2 (= 3 - 1) and a "foo" pointer as the parent.
    028 */
    029public class NullElementPointer extends CollectionPointer {
    030
    031    private static final long serialVersionUID = 8714236818791036721L;
    032
    033    /**
    034     * Constructs a new NullElementPointer.
    035     *
    036     * @param parent parent pointer
    037     * @param index  int
    038     */
    039    public NullElementPointer(final NodePointer parent, final int index) {
    040        super(parent, (Object) null);
    041        this.index = index;
    042    }
    043
    044    @Override
    045    public String asPath() {
    046        final StringBuilder buffer = new StringBuilder();
    047        final NodePointer parent = getImmediateParentPointer();
    048        if (parent != null) {
    049            buffer.append(parent.asPath());
    050        }
    051        if (index != WHOLE_COLLECTION) {
    052            // Address the list[1][2] case
    053            if (parent != null && parent.getIndex() != WHOLE_COLLECTION) {
    054                buffer.append("/.");
    055            } else if (parent != null && parent.getImmediateParentPointer() != null && parent.getImmediateParentPointer().getIndex() != WHOLE_COLLECTION) {
    056                buffer.append("/.");
    057            }
    058            buffer.append("[").append(index + 1).append(']');
    059        }
    060        return buffer.toString();
    061    }
    062
    063    @Override
    064    public NodePointer createPath(final JXPathContext context) {
    065        return parent.createChild(context, null, index);
    066    }
    067
    068    @Override
    069    public NodePointer createPath(final JXPathContext context, final Object value) {
    070        return parent.createChild(context, null, index, value);
    071    }
    072
    073    @Override
    074    public boolean equals(final Object object) {
    075        if (object == this) {
    076            return true;
    077        }
    078        if (!(object instanceof NullElementPointer)) {
    079            return false;
    080        }
    081        final NullElementPointer other = (NullElementPointer) object;
    082        return getImmediateParentPointer() == other.getImmediateParentPointer() && index == other.index;
    083    }
    084
    085    @Override
    086    public Object getBaseValue() {
    087        return null;
    088    }
    089
    090    @Override
    091    public Object getImmediateNode() {
    092        return null;
    093    }
    094
    095    @Override
    096    public int getLength() {
    097        return 0;
    098    }
    099
    100    @Override
    101    public QName getName() {
    102        return null;
    103    }
    104
    105    /**
    106     * Gets the property pointer for this.
    107     *
    108     * @return PropertyPointer
    109     */
    110    public PropertyPointer getPropertyPointer() {
    111        return new NullPropertyPointer(this);
    112    }
    113
    114    @Override
    115    public NodePointer getValuePointer() {
    116        return new NullPointer(this, getName());
    117    }
    118
    119    @Override
    120    public int hashCode() {
    121        return getImmediateParentPointer().hashCode() + index;
    122    }
    123
    124    @Override
    125    public boolean isActual() {
    126        return false;
    127    }
    128
    129    @Override
    130    public boolean isCollection() {
    131        return false;
    132    }
    133
    134    @Override
    135    public boolean isContainer() {
    136        return true;
    137    }
    138
    139    @Override
    140    public boolean isLeaf() {
    141        return true;
    142    }
    143
    144    @Override
    145    public void setValue(final Object value) {
    146        throw new UnsupportedOperationException("Collection element does not exist: " + this);
    147    }
    148}