1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.custom.crosstable;
20
21 import java.sql.ResultSet;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Map;
28
29 import javax.faces.application.FacesMessage;
30 import javax.faces.component.EditableValueHolder;
31 import javax.faces.component.UIComponent;
32 import javax.faces.component.UIData;
33 import javax.faces.context.FacesContext;
34 import javax.faces.el.ValueBinding;
35 import javax.faces.model.ArrayDataModel;
36 import javax.faces.model.DataModel;
37 import javax.faces.model.ListDataModel;
38 import javax.faces.model.ResultDataModel;
39 import javax.faces.model.ResultSetDataModel;
40 import javax.faces.model.ScalarDataModel;
41 import javax.servlet.jsp.jstl.sql.Result;
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 public class UIColumns extends UIData {
83 public static final String COMPONENT_TYPE = "org.apache.myfaces.Columns";
84
85 private static final Class OBJECT_ARRAY_CLASS = (new Object[0]).getClass();
86
87 private static final int PROCESS_DECODES = 1;
88 private static final int PROCESS_VALIDATORS = 2;
89 private static final int PROCESS_UPDATES = 3;
90
91 private boolean _isValidChilds = true;
92
93
94 private Map _cellStates = new HashMap();
95
96 private Object _initialDescendantComponentState = null;
97
98 private int _colIndex = -1;
99 private UIData _parentUIData;
100
101 private Map _dataModelMap = new HashMap();
102
103 public UIColumns() {
104 super();
105 }
106
107
108
109
110 public boolean isRowAvailable() {
111 return getDataModel().isRowAvailable();
112 }
113
114
115
116
117 public int getRowCount() {
118 return getDataModel().getRowCount();
119 }
120
121
122 public Object getRowData() {
123 return getDataModel().getRowData();
124 }
125
126
127 public int getRowIndex() {
128 return _colIndex;
129 }
130
131
132 public void setRowIndex(int colIndex) {
133 if (colIndex < -1) {
134 throw new IllegalArgumentException("colIndex is less than -1");
135 }
136
137 if (_colIndex == colIndex) {
138 return;
139 }
140
141 FacesContext facesContext = getFacesContext();
142
143 if (_colIndex == -1) {
144 if (_initialDescendantComponentState == null) {
145 _initialDescendantComponentState = saveDescendantComponentStates(getFacetsAndChildren());
146 }
147 } else {
148 _cellStates.put(getClientId(facesContext), saveDescendantComponentStates(getFacetsAndChildren()));
149 }
150
151 _colIndex = colIndex;
152
153 DataModel dataModel = getDataModel();
154 dataModel.setRowIndex(colIndex);
155
156 String var = getVar();
157 if (colIndex == -1) {
158 if (var != null) {
159 facesContext.getExternalContext().getRequestMap().remove(var);
160 }
161 } else {
162 if (var != null) {
163 if (isRowAvailable()) {
164 Object rowData = dataModel.getRowData();
165 facesContext.getExternalContext().getRequestMap().put(var, rowData);
166 } else {
167 facesContext.getExternalContext().getRequestMap().remove(var);
168 }
169 }
170 }
171
172 if (_colIndex == -1) {
173 restoreDescendantComponentStates(getFacetsAndChildren(), _initialDescendantComponentState);
174 } else {
175 Object rowState = _cellStates.get(getClientId(facesContext));
176 if (rowState == null) {
177 restoreDescendantComponentStates(getFacetsAndChildren(), _initialDescendantComponentState);
178 } else {
179 restoreDescendantComponentStates(getFacetsAndChildren(), rowState);
180 }
181 }
182 }
183
184 protected void restoreDescendantComponentStates(Iterator childIterator, Object state) {
185 Iterator descendantStateIterator = null;
186 while (childIterator.hasNext()) {
187 if (descendantStateIterator == null && state != null) {
188 descendantStateIterator = ((Collection) state).iterator();
189 }
190 UIComponent component = (UIComponent) childIterator.next();
191
192 component.setId(component.getId());
193 if (!component.isTransient()) {
194 Object childState = null;
195 Object descendantState = null;
196 if (descendantStateIterator != null && descendantStateIterator.hasNext()) {
197 Object[] object = (Object[]) descendantStateIterator.next();
198 childState = object[0];
199 descendantState = object[1];
200 }
201 if (component instanceof EditableValueHolder) {
202 ((EditableValueHolderState) childState).restoreState((EditableValueHolder) component);
203 }
204 restoreDescendantComponentStates(component.getFacetsAndChildren(), descendantState);
205 }
206 }
207 }
208
209 protected Object saveDescendantComponentStates(Iterator childIterator) {
210 Collection childStates = null;
211 while (childIterator.hasNext()) {
212 if (childStates == null) {
213 childStates = new ArrayList();
214 }
215 UIComponent child = (UIComponent) childIterator.next();
216 if (!child.isTransient()) {
217 Object descendantState = saveDescendantComponentStates(child.getFacetsAndChildren());
218 Object state = null;
219 if (child instanceof EditableValueHolder) {
220 state = new EditableValueHolderState((EditableValueHolder) child);
221 }
222 childStates.add(new Object[] { state, descendantState });
223 }
224 }
225 return childStates;
226 }
227
228 public void setValue(Object value) {
229 super.setValue(value);
230 _dataModelMap.clear();
231 _cellStates.clear();
232 _isValidChilds = true;
233 }
234
235 public void setValueBinding(String name, ValueBinding binding) {
236 if (name == null) {
237 throw new NullPointerException("name");
238 } else if (name.equals("value")) {
239 _dataModelMap.clear();
240 } else if (name.equals("var") || name.equals("rowIndex")) {
241 throw new IllegalArgumentException("name " + name);
242 }
243 super.setValueBinding(name, binding);
244 }
245
246
247
248
249
250 protected DataModel getDataModel() {
251 String clientID = "";
252 UIComponent parent = getParentUIData().getParent();
253 if (parent != null) {
254 clientID = parent.getClientId(getFacesContext());
255 }
256 DataModel dataModel = (DataModel) _dataModelMap.get(clientID);
257 if (dataModel == null) {
258 dataModel = createDataModel();
259 _dataModelMap.put(clientID, dataModel);
260 }
261 return dataModel;
262 }
263
264 protected void setDataModel(DataModel dataModel) {
265 if (dataModel == null && getParent() == null) {
266 return;
267 }
268 UIComponent parent = getParentUIData().getParent();
269 String clientID = "";
270 if (parent != null) {
271 clientID = parent.getClientId(getFacesContext());
272 }
273 _dataModelMap.put(clientID, dataModel);
274 }
275
276
277
278
279 protected DataModel createDataModel() {
280 Object value = getValue();
281 if (value == null) {
282 return EMPTY_DATA_MODEL;
283 } else if (value instanceof DataModel) {
284 return (DataModel) value;
285 } else if (value instanceof List) {
286 return new ListDataModel((List) value);
287 } else if (value instanceof Collection) {
288 return new ListDataModel(new ArrayList((Collection) value));
289 } else if (OBJECT_ARRAY_CLASS.isAssignableFrom(value.getClass())) {
290 return new ArrayDataModel((Object[]) value);
291 } else if (value instanceof ResultSet) {
292 return new ResultSetDataModel((ResultSet) value);
293 } else if (value instanceof Result) {
294 return new ResultDataModel((Result) value);
295 } else {
296 return new ScalarDataModel(value);
297 }
298 }
299
300 private static final DataModel EMPTY_DATA_MODEL = new DataModel() {
301 public boolean isRowAvailable() {
302 return false;
303 }
304
305 public int getRowCount() {
306 return 0;
307 }
308
309 public Object getRowData() {
310 throw new IllegalArgumentException();
311 }
312
313 public int getRowIndex() {
314 return -1;
315 }
316
317 public void setRowIndex(int i) {
318 if (i < -1)
319 throw new IndexOutOfBoundsException("Index < 0 : " + i);
320 }
321
322 public Object getWrappedData() {
323 return null;
324 }
325
326 public void setWrappedData(Object obj) {
327 if (obj == null)
328 return;
329 throw new UnsupportedOperationException(this.getClass().getName() + " UnsupportedOperationException");
330 }
331 };
332
333
334
335
336
337
338 public void processDecodes(FacesContext context) {
339 if (context == null)
340 throw new NullPointerException("context");
341 if (!isRendered())
342 return;
343
344 setRowIndex(-1);
345 processColumnsFacets(context, PROCESS_DECODES);
346 processRows(context, PROCESS_DECODES);
347 setRowIndex(-1);
348
349 try {
350 decode(context);
351 } catch (RuntimeException e) {
352 context.renderResponse();
353 throw e;
354 }
355 }
356
357 private void processColumnsFacets(FacesContext context, int processAction) {
358 int first = getFirst();
359 int cols = getRows();
360 int last;
361 if (cols == 0) {
362 last = getRowCount();
363 } else {
364 last = first + cols;
365 }
366
367 for (int colIndex = first; colIndex < last; colIndex++) {
368 setRowIndex(colIndex);
369 if (isRowAvailable()) {
370 for (Iterator facetsIter = getFacets().values().iterator(); facetsIter.hasNext();) {
371 UIComponent facet = (UIComponent) facetsIter.next();
372 process(context, facet, processAction);
373 }
374 }
375 }
376 setRowIndex(-1);
377 }
378
379 private void processRows(FacesContext context, int processAction) {
380 UIData parentUIData = getParentUIData();
381 int first = parentUIData.getFirst();
382 int rows = parentUIData.getRows();
383 int last;
384 if (rows == 0) {
385 last = parentUIData.getRowCount();
386 } else {
387 last = first + rows;
388 }
389
390 for (int rowIndex = first; rowIndex < last; rowIndex++) {
391 parentUIData.setRowIndex(rowIndex);
392 if (parentUIData.isRowAvailable()) {
393 processColumns(context, processAction);
394 }
395 }
396 }
397
398
399
400
401
402
403
404 private UIData getParentUIData() {
405 if (_parentUIData == null) {
406 UIComponent parent = getParent();
407 if (!(parent instanceof UIData)) {
408 throw new IllegalStateException("UIColumns component must be a child of a UIData component");
409 }
410 _parentUIData = (UIData) parent;
411 }
412 return _parentUIData;
413 }
414
415 private void processColumns(FacesContext context, int processAction) {
416 int first = getFirst();
417 int cols = getRows();
418 int last;
419 if (cols == 0) {
420 last = getRowCount();
421 } else {
422 last = first + cols;
423 }
424
425 for (int colIndex = first; colIndex < last; colIndex++) {
426 setRowIndex(colIndex);
427 if (isRowAvailable()) {
428 for (Iterator columnChildIter = getChildren().iterator(); columnChildIter.hasNext();) {
429 UIComponent columnChild = (UIComponent) columnChildIter.next();
430 process(context, columnChild, processAction);
431 }
432 }
433 }
434 setRowIndex(-1);
435 }
436
437
438
439
440 public void processValidators(FacesContext context) {
441 if (context == null)
442 throw new NullPointerException("context");
443 if (!isRendered())
444 return;
445 setRowIndex(-1);
446 processColumnsFacets(context, PROCESS_VALIDATORS);
447 processRows(context, PROCESS_VALIDATORS);
448 setRowIndex(-1);
449
450
451 if (context.getRenderResponse()) {
452 _isValidChilds = false;
453 }
454 }
455
456
457
458
459 public void processUpdates(FacesContext context) {
460 if (context == null)
461 throw new NullPointerException("context");
462 if (!isRendered())
463 return;
464 setRowIndex(-1);
465 processColumnsFacets(context, PROCESS_UPDATES);
466 processRows(context, PROCESS_UPDATES);
467 setRowIndex(-1);
468
469
470 if (context.getRenderResponse()) {
471 _isValidChilds = false;
472 }
473 }
474
475 private void process(FacesContext context, UIComponent component, int processAction) {
476 switch (processAction) {
477 case PROCESS_DECODES:
478 component.processDecodes(context);
479 break;
480 case PROCESS_VALIDATORS:
481 component.processValidators(context);
482 break;
483 case PROCESS_UPDATES:
484 component.processUpdates(context);
485 break;
486 }
487 }
488
489
490
491
492
493 public void encodeTableBegin(FacesContext context) {
494 setRowIndex(-1);
495 _initialDescendantComponentState = null;
496 if (_isValidChilds && !hasErrorMessages(context)) {
497
498 _dataModelMap.clear();
499 _cellStates.clear();
500 }
501 }
502
503 protected boolean hasErrorMessages(FacesContext context) {
504 for (Iterator iter = context.getMessages(); iter.hasNext();) {
505 FacesMessage message = (FacesMessage) iter.next();
506 if (FacesMessage.SEVERITY_ERROR.compareTo(message.getSeverity()) <= 0) {
507 return true;
508 }
509 }
510 return false;
511 }
512
513
514
515
516
517 public void encodeTableEnd(FacesContext context) {
518 setRowIndex(-1);
519 }
520
521 private class EditableValueHolderState {
522 private final Object _value;
523 private final boolean _localValueSet;
524 private final boolean _valid;
525 private final Object _submittedValue;
526
527 public EditableValueHolderState(EditableValueHolder evh) {
528 _value = evh.getLocalValue();
529 _localValueSet = evh.isLocalValueSet();
530 _valid = evh.isValid();
531 _submittedValue = evh.getSubmittedValue();
532 }
533
534 public void restoreState(EditableValueHolder evh) {
535 evh.setValue(_value);
536 evh.setLocalValueSet(_localValueSet);
537 evh.setValid(_valid);
538 evh.setSubmittedValue(_submittedValue);
539 }
540 }
541
542
543
544 public String getClientId(FacesContext context) {
545 String clientId2 = super.getClientId(context);
546 int rowIndex = getRowIndex();
547 if (rowIndex == -1) {
548 return clientId2;
549 }
550 else {
551 return clientId2 + "_" + rowIndex;
552 }
553 }
554
555
556 }