1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.jxpath.ri.model.dynamic;
19
20 import java.util.Arrays;
21 import java.util.Map;
22
23 import org.apache.commons.jxpath.AbstractFactory;
24 import org.apache.commons.jxpath.DynamicPropertyHandler;
25 import org.apache.commons.jxpath.JXPathAbstractFactoryException;
26 import org.apache.commons.jxpath.JXPathContext;
27 import org.apache.commons.jxpath.JXPathInvalidAccessException;
28 import org.apache.commons.jxpath.ri.model.NodePointer;
29 import org.apache.commons.jxpath.ri.model.beans.PropertyPointer;
30 import org.apache.commons.jxpath.util.ValueUtils;
31
32
33
34
35 public class DynamicPropertyPointer extends PropertyPointer {
36
37 private static final long serialVersionUID = -5720585681149150822L;
38
39
40
41
42 private final DynamicPropertyHandler handler;
43
44
45 private String name;
46
47
48 private String[] names;
49
50
51
52
53 private String requiredPropertyName;
54
55
56
57
58
59
60
61 public DynamicPropertyPointer(final NodePointer parent, final DynamicPropertyHandler handler) {
62 super(parent);
63 this.handler = handler;
64 }
65
66 @Override
67 public String asPath() {
68 final StringBuilder buffer = new StringBuilder();
69 buffer.append(getImmediateParentPointer().asPath());
70 if (buffer.length() == 0) {
71 buffer.append("/.");
72 } else if (buffer.charAt(buffer.length() - 1) == '/') {
73 buffer.append('.');
74 }
75 buffer.append("[@name='");
76 buffer.append(escape(getPropertyName()));
77 buffer.append("']");
78 if (index != WHOLE_COLLECTION && isCollection()) {
79 buffer.append('[').append(index + 1).append(']');
80 }
81 return buffer.toString();
82 }
83
84 @Override
85 public NodePointer createPath(final JXPathContext context) {
86
87 Object collection = getBaseValue();
88 if (collection == null) {
89 final AbstractFactory factory = getAbstractFactory(context);
90 final boolean success = factory.createObject(context, this, getBean(), getPropertyName(), 0);
91 if (!success) {
92 throw new JXPathAbstractFactoryException("Factory could not create an object for path: " + asPath());
93 }
94 collection = getBaseValue();
95 }
96 if (index != WHOLE_COLLECTION) {
97 if (index < 0) {
98 throw new JXPathInvalidAccessException("Index is less than 1: " + asPath());
99 }
100 if (index >= getLength()) {
101 collection = ValueUtils.expandCollection(collection, index + 1);
102 handler.setProperty(getBean(), getPropertyName(), collection);
103 }
104 }
105 return this;
106 }
107
108 @Override
109 public NodePointer createPath(final JXPathContext context, final Object value) {
110 if (index == WHOLE_COLLECTION) {
111 handler.setProperty(getBean(), getPropertyName(), value);
112 } else {
113 createPath(context);
114 ValueUtils.setValue(getBaseValue(), index, value);
115 }
116 return this;
117 }
118
119
120
121
122
123
124 @Override
125 public Object getBaseValue() {
126 return handler.getProperty(getBean(), getPropertyName());
127 }
128
129
130
131
132
133
134
135 @Override
136 public Object getImmediateNode() {
137 Object value;
138 if (index == WHOLE_COLLECTION) {
139 value = ValueUtils.getValue(handler.getProperty(getBean(), getPropertyName()));
140 } else {
141 value = ValueUtils.getValue(handler.getProperty(getBean(), getPropertyName()), index);
142 }
143 return value;
144 }
145
146
147
148
149
150
151 @Override
152 public int getPropertyCount() {
153 return getPropertyNames().length;
154 }
155
156
157
158
159
160
161 @Override
162 public int getPropertyIndex() {
163 if (propertyIndex == UNSPECIFIED_PROPERTY) {
164 final String[] names = getPropertyNames();
165 for (int i = 0; i < names.length; i++) {
166 if (names[i].equals(name)) {
167 setPropertyIndex(i);
168 break;
169 }
170 }
171 }
172 return super.getPropertyIndex();
173 }
174
175
176
177
178
179
180 @Override
181 public String getPropertyName() {
182 if (name == null) {
183 final String[] names = getPropertyNames();
184 name = propertyIndex >= 0 && propertyIndex < names.length ? names[propertyIndex] : "*";
185 }
186 return name;
187 }
188
189
190
191
192
193
194 @Override
195 public String[] getPropertyNames() {
196 if (names == null) {
197 String[] allNames = handler.getPropertyNames(getBean());
198 names = new String[allNames.length];
199 System.arraycopy(allNames, 0, names, 0, names.length);
200 Arrays.sort(names);
201 if (requiredPropertyName != null) {
202 final int inx = Arrays.binarySearch(names, requiredPropertyName);
203 if (inx < 0) {
204 allNames = names;
205 names = new String[allNames.length + 1];
206 names[0] = requiredPropertyName;
207 System.arraycopy(allNames, 0, names, 1, allNames.length);
208 Arrays.sort(names);
209 }
210 }
211 }
212 return names;
213 }
214
215
216
217
218
219
220 @Override
221 protected boolean isActualProperty() {
222 return true;
223 }
224
225
226
227
228
229
230 @Override
231 public boolean isContainer() {
232 return true;
233 }
234
235 @Override
236 public void remove() {
237 if (index == WHOLE_COLLECTION) {
238 removeKey();
239 } else if (isCollection()) {
240 final Object collection = ValueUtils.remove(getBaseValue(), index);
241 handler.setProperty(getBean(), getPropertyName(), collection);
242 } else if (index == 0) {
243 removeKey();
244 }
245 }
246
247
248
249
250 private void removeKey() {
251 final Object bean = getBean();
252 if (bean instanceof Map) {
253 ((Map) bean).remove(getPropertyName());
254 } else {
255 handler.setProperty(bean, getPropertyName(), null);
256 }
257 }
258
259
260
261
262
263
264 @Override
265 public void setPropertyIndex(final int index) {
266 if (propertyIndex != index) {
267 super.setPropertyIndex(index);
268 name = null;
269 }
270 }
271
272
273
274
275
276
277
278 @Override
279 public void setPropertyName(final String propertyName) {
280 setPropertyIndex(UNSPECIFIED_PROPERTY);
281 this.name = propertyName;
282 requiredPropertyName = propertyName;
283 if (names != null && Arrays.binarySearch(names, propertyName) < 0) {
284 names = null;
285 }
286 }
287
288
289
290
291
292
293
294 @Override
295 public void setValue(final Object value) {
296 if (index == WHOLE_COLLECTION) {
297 handler.setProperty(getBean(), getPropertyName(), value);
298 } else {
299 ValueUtils.setValue(handler.getProperty(getBean(), getPropertyName()), index, value);
300 }
301 }
302 }