001: /*
002: * Copyright 1999-2004 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.apache.commons.jxpath.ri.model.beans;
017:
018: import org.apache.commons.jxpath.AbstractFactory;
019: import org.apache.commons.jxpath.JXPathContext;
020: import org.apache.commons.jxpath.JXPathException;
021: import org.apache.commons.jxpath.JXPathIntrospector;
022: import org.apache.commons.jxpath.ri.QName;
023: import org.apache.commons.jxpath.ri.model.NodePointer;
024: import org.apache.commons.jxpath.util.ValueUtils;
025:
026: /**
027: * A pointer allocated by a PropertyOwnerPointer to represent the value of
028: * a property of the parent object.
029: *
030: * @author Dmitri Plotnikov
031: * @version $Revision: 1.14 $ $Date: 2004/04/04 22:06:36 $
032: */
033: public abstract class PropertyPointer extends NodePointer {
034: public static final int UNSPECIFIED_PROPERTY = Integer.MIN_VALUE;
035:
036: protected int propertyIndex = UNSPECIFIED_PROPERTY;
037: protected Object bean;
038:
039: /**
040: * Takes a javabean, a descriptor of a property of that object and
041: * an offset within that property (starting with 0).
042: */
043: public PropertyPointer(NodePointer parent) {
044: super (parent);
045: }
046:
047: public int getPropertyIndex() {
048: return propertyIndex;
049: }
050:
051: public void setPropertyIndex(int index) {
052: if (propertyIndex != index) {
053: propertyIndex = index;
054: setIndex(WHOLE_COLLECTION);
055: }
056: }
057:
058: public Object getBean() {
059: if (bean == null) {
060: bean = getImmediateParentPointer().getNode();
061: }
062: return bean;
063: }
064:
065: public QName getName() {
066: return new QName(null, getPropertyName());
067: }
068:
069: public abstract String getPropertyName();
070:
071: public abstract void setPropertyName(String propertyName);
072:
073: public abstract int getPropertyCount();
074:
075: public abstract String[] getPropertyNames();
076:
077: protected abstract boolean isActualProperty();
078:
079: public boolean isActual() {
080: if (!isActualProperty()) {
081: return false;
082: }
083:
084: return super .isActual();
085: }
086:
087: private static final Object UNINITIALIZED = new Object();
088:
089: private Object value = UNINITIALIZED;
090:
091: public Object getImmediateNode() {
092: if (value == UNINITIALIZED) {
093: if (index == WHOLE_COLLECTION) {
094: value = ValueUtils.getValue(getBaseValue());
095: } else {
096: value = ValueUtils.getValue(getBaseValue(), index);
097: }
098: }
099: return value;
100: }
101:
102: public boolean isCollection() {
103: Object value = getBaseValue();
104: return value != null && ValueUtils.isCollection(value);
105: }
106:
107: public boolean isLeaf() {
108: Object value = getNode();
109: return value == null
110: || JXPathIntrospector.getBeanInfo(value.getClass())
111: .isAtomic();
112: }
113:
114: /**
115: * If the property contains a collection, then the length of that
116: * collection, otherwise - 1.
117: */
118: public int getLength() {
119: return ValueUtils.getLength(getBaseValue());
120: }
121:
122: /**
123: * Returns a NodePointer that can be used to access the currently
124: * selected property value.
125: */
126: public NodePointer getImmediateValuePointer() {
127: return NodePointer.newChildNodePointer(this , getName(),
128: getImmediateNode());
129: }
130:
131: public NodePointer createPath(JXPathContext context) {
132: if (getImmediateNode() == null) {
133: AbstractFactory factory = getAbstractFactory(context);
134: int inx = (index == WHOLE_COLLECTION ? 0 : index);
135: boolean success = factory.createObject(context, this ,
136: getBean(), getPropertyName(), inx);
137: if (!success) {
138: throw new JXPathException("Factory " + factory
139: + " could not create an object for path: "
140: + asPath());
141: }
142: }
143: return this ;
144: }
145:
146: public NodePointer createPath(JXPathContext context, Object value) {
147: // If neccessary, expand collection
148: if (index != WHOLE_COLLECTION && index >= getLength()) {
149: createPath(context);
150: }
151: setValue(value);
152: return this ;
153: }
154:
155: public NodePointer createChild(JXPathContext context, QName name,
156: int index, Object value) {
157: PropertyPointer prop = (PropertyPointer) clone();
158: if (name != null) {
159: prop.setPropertyName(name.toString());
160: }
161: prop.setIndex(index);
162: return prop.createPath(context, value);
163: }
164:
165: public NodePointer createChild(JXPathContext context, QName name,
166: int index) {
167: PropertyPointer prop = (PropertyPointer) clone();
168: if (name != null) {
169: prop.setPropertyName(name.toString());
170: }
171: prop.setIndex(index);
172: return prop.createPath(context);
173: }
174:
175: public int hashCode() {
176: return getImmediateParentPointer().hashCode() + propertyIndex
177: + index;
178: }
179:
180: public boolean equals(Object object) {
181: if (object == this ) {
182: return true;
183: }
184:
185: if (!(object instanceof PropertyPointer)) {
186: return false;
187: }
188:
189: PropertyPointer other = (PropertyPointer) object;
190: if (parent != other.parent) {
191: if (parent == null || !parent.equals(other.parent)) {
192: return false;
193: }
194: }
195:
196: if (getPropertyIndex() != other.getPropertyIndex()
197: || !getPropertyName().equals(other.getPropertyName())) {
198: return false;
199: }
200:
201: int iThis = (index == WHOLE_COLLECTION ? 0 : index);
202: int iOther = (other.index == WHOLE_COLLECTION ? 0 : other.index);
203: return iThis == iOther;
204: }
205:
206: public int compareChildNodePointers(NodePointer pointer1,
207: NodePointer pointer2) {
208: return getValuePointer().compareChildNodePointers(pointer1,
209: pointer2);
210: }
211:
212: private AbstractFactory getAbstractFactory(JXPathContext context) {
213: AbstractFactory factory = context.getFactory();
214: if (factory == null) {
215: throw new JXPathException("Factory is not set on the "
216: + "JXPathContext - cannot create path: " + asPath());
217: }
218: return factory;
219: }
220: }
|