1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.commons.jxpath.ri.model.beans;
17
18 import org.apache.commons.jxpath.AbstractFactory;
19 import org.apache.commons.jxpath.JXPathContext;
20 import org.apache.commons.jxpath.JXPathException;
21 import org.apache.commons.jxpath.JXPathIntrospector;
22 import org.apache.commons.jxpath.ri.QName;
23 import org.apache.commons.jxpath.ri.model.NodePointer;
24 import org.apache.commons.jxpath.util.ValueUtils;
25
26 /***
27 * A pointer allocated by a PropertyOwnerPointer to represent the value of
28 * a property of the parent object.
29 *
30 * @author Dmitri Plotnikov
31 * @version $Revision: 1.14 $ $Date: 2004/04/04 22:06:36 $
32 */
33 public abstract class PropertyPointer extends NodePointer {
34 public static final int UNSPECIFIED_PROPERTY = Integer.MIN_VALUE;
35
36 protected int propertyIndex = UNSPECIFIED_PROPERTY;
37 protected Object bean;
38
39 /***
40 * Takes a javabean, a descriptor of a property of that object and
41 * an offset within that property (starting with 0).
42 */
43 public PropertyPointer(NodePointer parent) {
44 super(parent);
45 }
46
47 public int getPropertyIndex() {
48 return propertyIndex;
49 }
50
51 public void setPropertyIndex(int index) {
52 if (propertyIndex != index) {
53 propertyIndex = index;
54 setIndex(WHOLE_COLLECTION);
55 }
56 }
57
58 public Object getBean() {
59 if (bean == null) {
60 bean = getImmediateParentPointer().getNode();
61 }
62 return bean;
63 }
64
65 public QName getName() {
66 return new QName(null, getPropertyName());
67 }
68
69 public abstract String getPropertyName();
70
71 public abstract void setPropertyName(String propertyName);
72
73 public abstract int getPropertyCount();
74
75 public abstract String[] getPropertyNames();
76
77 protected abstract boolean isActualProperty();
78
79 public boolean isActual() {
80 if (!isActualProperty()) {
81 return false;
82 }
83
84 return super.isActual();
85 }
86
87 private static final Object UNINITIALIZED = new Object();
88
89 private Object value = UNINITIALIZED;
90 public Object getImmediateNode() {
91 if (value == UNINITIALIZED) {
92 if (index == WHOLE_COLLECTION) {
93 value = ValueUtils.getValue(getBaseValue());
94 }
95 else {
96 value = ValueUtils.getValue(getBaseValue(), index);
97 }
98 }
99 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()).isAtomic();
111 }
112
113 /***
114 * If the property contains a collection, then the length of that
115 * collection, otherwise - 1.
116 */
117 public int getLength() {
118 return ValueUtils.getLength(getBaseValue());
119 }
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(
128 this,
129 getName(),
130 getImmediateNode());
131 }
132
133 public NodePointer createPath(JXPathContext context) {
134 if (getImmediateNode() == null) {
135 AbstractFactory factory = getAbstractFactory(context);
136 int inx = (index == WHOLE_COLLECTION ? 0 : index);
137 boolean success =
138 factory.createObject(
139 context,
140 this,
141 getBean(),
142 getPropertyName(),
143 inx);
144 if (!success) {
145 throw new JXPathException(
146 "Factory "
147 + factory
148 + " could not create an object for path: "
149 + asPath());
150 }
151 }
152 return this;
153 }
154
155 public NodePointer createPath(JXPathContext context, Object value) {
156
157 if (index != WHOLE_COLLECTION && index >= getLength()) {
158 createPath(context);
159 }
160 setValue(value);
161 return this;
162 }
163
164 public NodePointer createChild(
165 JXPathContext context,
166 QName name,
167 int index,
168 Object value)
169 {
170 PropertyPointer prop = (PropertyPointer) clone();
171 if (name != null) {
172 prop.setPropertyName(name.toString());
173 }
174 prop.setIndex(index);
175 return prop.createPath(context, value);
176 }
177
178 public NodePointer createChild(
179 JXPathContext context,
180 QName name,
181 int index)
182 {
183 PropertyPointer prop = (PropertyPointer) clone();
184 if (name != null) {
185 prop.setPropertyName(name.toString());
186 }
187 prop.setIndex(index);
188 return prop.createPath(context);
189 }
190
191 public int hashCode() {
192 return getImmediateParentPointer().hashCode() + propertyIndex + index;
193 }
194
195 public boolean equals(Object object) {
196 if (object == this) {
197 return true;
198 }
199
200 if (!(object instanceof PropertyPointer)) {
201 return false;
202 }
203
204 PropertyPointer other = (PropertyPointer) object;
205 if (parent != other.parent) {
206 if (parent == null || !parent.equals(other.parent)) {
207 return false;
208 }
209 }
210
211 if (getPropertyIndex() != other.getPropertyIndex()
212 || !getPropertyName().equals(other.getPropertyName())) {
213 return false;
214 }
215
216 int iThis = (index == WHOLE_COLLECTION ? 0 : index);
217 int iOther = (other.index == WHOLE_COLLECTION ? 0 : other.index);
218 return iThis == iOther;
219 }
220
221 public int compareChildNodePointers(
222 NodePointer pointer1,
223 NodePointer pointer2)
224 {
225 return getValuePointer().compareChildNodePointers(pointer1, pointer2);
226 }
227
228 private AbstractFactory getAbstractFactory(JXPathContext context) {
229 AbstractFactory factory = context.getFactory();
230 if (factory == null) {
231 throw new JXPathException(
232 "Factory is not set on the "
233 + "JXPathContext - cannot create path: "
234 + asPath());
235 }
236 return factory;
237 }
238 }