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}