1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.trinidad.model;
20
21 import java.lang.reflect.Array;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.List;
25
26 import javax.faces.model.DataModel;
27
28 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
29 import org.apache.myfaces.trinidad.util.CollectionUtils;
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95 public class ChildPropertyTreeModel extends TreeModel
96 {
97
98
99
100
101
102
103
104
105
106
107
108
109 public ChildPropertyTreeModel(Object instance, String childProperty)
110 {
111 this();
112 setChildProperty(childProperty);
113 setWrappedData(instance);
114 }
115
116
117
118
119
120
121 public ChildPropertyTreeModel()
122 {
123 Node root = new Node(null);
124 _path.add(root);
125 }
126
127
128
129
130 @Override
131 public Object getRowKey()
132 {
133 final int sz = _path.size() - 1;
134 Object lastRowkey = _getRowKey();
135 if ((sz == 0) && (lastRowkey == null))
136 return null;
137
138
139
140
141 List<Object> path = new ArrayList<Object>(sz+1);
142 if (sz > 0)
143 {
144 for(int i=0; i<sz; i++)
145 {
146 Node node = _getNode(i);
147 path.add(node.childModel.getRowKey());
148 }
149 }
150 path.add(lastRowkey);
151 return path;
152 }
153
154
155
156
157
158
159 @SuppressWarnings("unchecked")
160 @Override
161 public void setRowKey(Object rowKey)
162 {
163 Node root = _getNode(0);
164 _path.clear();
165 _path.add(root);
166
167 List<Object> path = (List<Object>) rowKey;
168 if ((path == null) || (path.size() == 0))
169 {
170 setRowIndex(-1);
171 return;
172 }
173
174 int lastIndex = path.size() - 1;
175 for(int i=0; i<lastIndex; i++)
176 {
177 Object pathKey = path.get(i);
178 _setRowKey(pathKey);
179 if (!isRowAvailable())
180 {
181
182
183 _path.clear();
184 _path.add(root);
185 setRowIndex(-1);
186 return;
187 }
188 enterContainer();
189 }
190
191 _setRowKey(path.get(lastIndex));
192 }
193
194 @SuppressWarnings("unchecked")
195 @Override
196 public Object getContainerRowKey(Object childKey)
197 {
198 List<Object> path = (List<Object>) childKey;
199 if ((path == null) || (path.size() <= 1))
200 return null;
201
202
203
204 return CollectionUtils.newSerializableList(path.subList(0, path.size() - 1));
205 }
206
207 @Override
208 public int getRowCount()
209 {
210 return _getModel().getRowCount();
211 }
212
213 @Override
214 public Object getRowData()
215 {
216 return _getModel().getRowData();
217 }
218
219 @Override
220 public boolean isRowAvailable()
221 {
222 return _getModel().isRowAvailable();
223 }
224
225 @Override
226 public boolean isContainer()
227 {
228 Object rowData = getRowData();
229 Object value = getChildData(rowData);
230
231 if (value != null)
232 {
233 if (value instanceof Collection<?>)
234 {
235 return !((Collection<?>)value).isEmpty();
236 }
237 else if (value.getClass().isArray())
238 {
239 return Array.getLength(value) > 0;
240 }
241 else if (value instanceof DataModel)
242 {
243 return ((DataModel)value).getRowCount() > 0;
244 }
245 }
246
247 return value != null;
248 }
249
250 @Override
251 public void enterContainer()
252 {
253 Object rowData = getRowData();
254 if (rowData == null)
255 throw new IllegalStateException(_LOG.getMessage(
256 "NULL_ROWDATA"));
257 Node node = new Node(rowData);
258 _path.add(node);
259 }
260
261 @Override
262 public void exitContainer()
263 {
264 int sz = _path.size();
265 if (sz > 1)
266 _path.remove(sz - 1);
267 else
268 throw new IllegalStateException(_LOG.getMessage(
269 "CANNOT_EXIT_ROOT_CONTAINER"));
270 }
271
272
273
274
275 @Override
276 public Object getWrappedData()
277 {
278 return _wrappedData;
279 }
280
281
282
283
284
285 @Override
286 public void setWrappedData(Object data)
287 {
288 Node root = _getNode(0);
289 root.childModel = ModelUtils.toCollectionModel(data);
290 setRowKey(null);
291 _wrappedData = data;
292 }
293
294
295
296
297 public final String getChildProperty()
298 {
299 return _childProperty;
300 }
301
302
303
304
305 public final void setChildProperty(String childProperty)
306 {
307 _childProperty = childProperty;
308 }
309
310 @Override
311 public int getRowIndex()
312 {
313 return _getModel().getRowIndex();
314 }
315
316 @Override
317 public void setRowIndex(int rowIndex)
318 {
319 _getModel().setRowIndex(rowIndex);
320 }
321
322 @Override
323 public boolean isSortable(String property)
324 {
325 return _getModel().isSortable(property);
326 }
327
328 @Override
329 public List<SortCriterion> getSortCriteria()
330 {
331 return _getModel().getSortCriteria();
332 }
333
334 @Override
335 public void setSortCriteria(List<SortCriterion> criteria)
336 {
337 _getModel().setSortCriteria(criteria);
338 }
339
340
341
342
343
344
345
346
347
348 protected Object getChildData(Object parentData)
349 {
350 String prop = getChildProperty();
351 if (prop == null)
352 return null;
353
354 return SortableModel.__resolveProperty(parentData, prop);
355 }
356
357
358
359
360
361
362 protected CollectionModel createChildModel(Object childData)
363 {
364 CollectionModel model = ModelUtils.toCollectionModel(childData);
365 model.setRowIndex(-1);
366 return model;
367 }
368
369 private Object _getRowKey()
370 {
371 return _getModel().getRowKey();
372 }
373
374 private void _setRowKey(Object key)
375 {
376 _getModel().setRowKey(key);
377 }
378
379 private Node _getCurrentNode()
380 {
381 return _getNode(_path.size() - 1);
382 }
383
384 private Node _getNode(int index)
385 {
386 return _path.get(index);
387 }
388
389 private CollectionModel _getModel()
390 {
391 Node node = _getCurrentNode();
392 CollectionModel model = node.childModel;
393
394 if (model == null)
395 {
396 Object value = getChildData(node.parentData);
397 model = createChildModel(value);
398 node.childModel = model;
399 }
400 return model;
401 }
402
403 private static final class Node
404 {
405 public final Object parentData;
406 public CollectionModel childModel = null;
407
408 public Node(Object parentData)
409 {
410 this.parentData = parentData;
411 }
412 }
413
414 private final List<Node> _path = new ArrayList<Node>(5);
415 private String _childProperty = null;
416 private Object _wrappedData = null;
417 private static final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(
418 ChildPropertyTreeModel.class);
419 }