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 java.beans.IndexedPropertyDescriptor;
19 import java.beans.PropertyDescriptor;
20
21 import org.apache.commons.jxpath.JXPathBeanInfo;
22 import org.apache.commons.jxpath.JXPathContext;
23 import org.apache.commons.jxpath.JXPathException;
24 import org.apache.commons.jxpath.ri.model.NodePointer;
25 import org.apache.commons.jxpath.util.ValueUtils;
26
27 /***
28 * Pointer pointing to a property of a JavaBean.
29 *
30 * @author Dmitri Plotnikov
31 * @version $Revision: 1.17 $ $Date: 2004/04/04 22:06:36 $
32 */
33 public class BeanPropertyPointer extends PropertyPointer {
34 private String propertyName;
35 private JXPathBeanInfo beanInfo;
36 private PropertyDescriptor propertyDescriptors[];
37 private PropertyDescriptor propertyDescriptor;
38 private String[] names;
39 private static final Object UNINITIALIZED = new Object();
40 private Object baseValue = UNINITIALIZED;
41 private Object value = UNINITIALIZED;
42
43 private static final int UNKNOWN_LENGTH_MAX_COUNT = 10000;
44
45 public BeanPropertyPointer(NodePointer parent, JXPathBeanInfo beanInfo) {
46 super(parent);
47 this.beanInfo = beanInfo;
48 }
49
50 /***
51 * This type of node is auxiliary.
52 */
53 public boolean isContainer() {
54 return true;
55 }
56
57 /***
58 * Number of the bean's properties.
59 */
60 public int getPropertyCount() {
61 return getPropertyDescriptors().length;
62 }
63
64 /***
65 * Names of all properties, sorted alphabetically
66 */
67 public String[] getPropertyNames() {
68 if (names == null) {
69 PropertyDescriptor pds[] = getPropertyDescriptors();
70 names = new String[pds.length];
71 for (int i = 0; i < names.length; i++) {
72 names[i] = pds[i].getName();
73 }
74 }
75 return names;
76 }
77
78 /***
79 * Select a property by name
80 */
81 public void setPropertyName(String propertyName) {
82 setPropertyIndex(UNSPECIFIED_PROPERTY);
83 this.propertyName = propertyName;
84 }
85
86 /***
87 * Selects a property by its offset in the alphabetically sorted list.
88 */
89 public void setPropertyIndex(int index) {
90 if (propertyIndex != index) {
91 super.setPropertyIndex(index);
92 propertyName = null;
93 propertyDescriptor = null;
94 baseValue = UNINITIALIZED;
95 value = UNINITIALIZED;
96 }
97 }
98
99 /***
100 * The value of the currently selected property.
101 */
102 public Object getBaseValue() {
103 if (baseValue == UNINITIALIZED) {
104 PropertyDescriptor pd = getPropertyDescriptor();
105 if (pd == null) {
106 return null;
107 }
108 baseValue = ValueUtils.getValue(getBean(), pd);
109 }
110 return baseValue;
111 }
112
113 public void setIndex(int index) {
114 if (this.index != index) {
115
116
117 if (this.index != WHOLE_COLLECTION
118 || index != 0
119 || isCollection()) {
120 super.setIndex(index);
121 value = UNINITIALIZED;
122 }
123 }
124 }
125
126 /***
127 * If index == WHOLE_COLLECTION, the value of the property, otherwise
128 * the value of the index'th element of the collection represented by the
129 * property. If the property is not a collection, index should be zero
130 * and the value will be the property itself.
131 */
132 public Object getImmediateNode() {
133 if (value == UNINITIALIZED) {
134 if (index == WHOLE_COLLECTION) {
135 value = ValueUtils.getValue(getBaseValue());
136 }
137 else {
138 PropertyDescriptor pd = getPropertyDescriptor();
139 if (pd == null) {
140 value = null;
141 }
142 else {
143 value = ValueUtils.getValue(getBean(), pd, index);
144 }
145 }
146 }
147 return value;
148 }
149
150 protected boolean isActualProperty() {
151 return getPropertyDescriptor() != null;
152 }
153
154 public boolean isCollection() {
155 PropertyDescriptor pd = getPropertyDescriptor();
156 if (pd == null) {
157 return false;
158 }
159
160 if (pd instanceof IndexedPropertyDescriptor) {
161 return true;
162 }
163
164 int hint = ValueUtils.getCollectionHint(pd.getPropertyType());
165 if (hint == -1) {
166 return false;
167 }
168 if (hint == 1) {
169 return true;
170 }
171
172 Object value = getBaseValue();
173 return value != null && ValueUtils.isCollection(value);
174 }
175
176 /***
177 * If the property contains a collection, then the length of that
178 * collection, otherwise - 1.
179 */
180 public int getLength() {
181 PropertyDescriptor pd = getPropertyDescriptor();
182 if (pd == null) {
183 return 1;
184 }
185
186 if (pd instanceof IndexedPropertyDescriptor) {
187 return ValueUtils.getIndexedPropertyLength(
188 getBean(),
189 (IndexedPropertyDescriptor) pd);
190 }
191
192 int hint = ValueUtils.getCollectionHint(pd.getPropertyType());
193 if (hint == -1) {
194 return 1;
195 }
196 return ValueUtils.getLength(getBaseValue());
197 }
198
199 /***
200 * If index == WHOLE_COLLECTION, change the value of the property, otherwise
201 * change the value of the index'th element of the collection
202 * represented by the property.
203 */
204 public void setValue(Object value) {
205 PropertyDescriptor pd = getPropertyDescriptor();
206 if (pd == null) {
207 throw new JXPathException(
208 "Cannot set property: " + asPath() + " - no such property");
209 }
210
211 if (index == WHOLE_COLLECTION) {
212 ValueUtils.setValue(getBean(), pd, value);
213 }
214 else {
215 ValueUtils.setValue(getBean(), pd, index, value);
216 }
217 this.value = value;
218 }
219
220 /***
221 * @see PropertyPointer#createPath(JXPathContext)
222 */
223 public NodePointer createPath(JXPathContext context) {
224 if (getImmediateNode() == null) {
225 super.createPath(context);
226 baseValue = UNINITIALIZED;
227 value = UNINITIALIZED;
228 }
229 return this;
230 }
231
232 public void remove() {
233 if (index == WHOLE_COLLECTION) {
234 setValue(null);
235 }
236 else if (isCollection()) {
237 Object collection = ValueUtils.remove(getBaseValue(), index);
238 ValueUtils.setValue(getBean(), getPropertyDescriptor(), collection);
239 }
240 else if (index == 0) {
241 index = WHOLE_COLLECTION;
242 setValue(null);
243 }
244 }
245
246 /***
247 * Name of the currently selected property.
248 */
249 public String getPropertyName() {
250 if (propertyName == null) {
251 PropertyDescriptor pd = getPropertyDescriptor();
252 if (pd != null) {
253 propertyName = pd.getName();
254 }
255 }
256 return propertyName != null ? propertyName : "*";
257 }
258
259 /***
260 * Finds the property descriptor corresponding to the current property
261 * index.
262 */
263 private PropertyDescriptor getPropertyDescriptor() {
264 if (propertyDescriptor == null) {
265 int inx = getPropertyIndex();
266 if (inx == UNSPECIFIED_PROPERTY) {
267 propertyDescriptor =
268 beanInfo.getPropertyDescriptor(propertyName);
269 }
270 else {
271 PropertyDescriptor propertyDescriptors[] =
272 getPropertyDescriptors();
273 if (inx >= 0 && inx < propertyDescriptors.length) {
274 propertyDescriptor = propertyDescriptors[inx];
275 }
276 else {
277 propertyDescriptor = null;
278 }
279 }
280 }
281 return propertyDescriptor;
282 }
283
284 protected PropertyDescriptor[] getPropertyDescriptors() {
285 if (propertyDescriptors == null) {
286 propertyDescriptors = beanInfo.getPropertyDescriptors();
287 }
288 return propertyDescriptors;
289 }
290 }