1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.component.html.ext;
20
21 import java.io.IOException;
22 import java.sql.ResultSet;
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.HashMap;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.Map;
29
30 import javax.faces.application.FacesMessage;
31 import javax.faces.component.EditableValueHolder;
32 import javax.faces.component.NamingContainer;
33 import javax.faces.component.UIComponent;
34 import javax.faces.context.FacesContext;
35 import javax.faces.el.ValueBinding;
36 import javax.faces.model.ArrayDataModel;
37 import javax.faces.model.DataModel;
38 import javax.faces.model.ListDataModel;
39 import javax.faces.model.ResultDataModel;
40 import javax.faces.model.ResultSetDataModel;
41 import javax.faces.model.ScalarDataModel;
42 import javax.servlet.jsp.jstl.sql.Result;
43
44 import org.apache.myfaces.component.html.util.HtmlComponentUtils;
45 import org.apache.myfaces.custom.ExtendedComponentBase;
46
47
48
49
50
51
52
53
54
55
56
57 public abstract class HtmlDataTableHack extends
58 javax.faces.component.html.HtmlDataTable implements
59 ExtendedComponentBase
60
61 {
62 private Map _dataModelMap = new HashMap();
63
64
65 private boolean _isValidChilds = true;
66
67
68 private Map _rowStates = new HashMap();
69
70
71 private Object _initialDescendantComponentState = null;
72
73
74
75
76
77 private static final Class OBJECT_ARRAY_CLASS = (new Object[0]).getClass();
78
79 private static final boolean DEFAULT_PRESERVEROWSTATES = false;
80
81 private static final String UNIQUE_ROW_ID_PREFIX = "r_id_";
82
83 private int _rowIndex = -1;
84
85 private Boolean _preserveRowStates;
86
87 public boolean isRowAvailable()
88 {
89 return getDataModel().isRowAvailable();
90 }
91
92 public int getRowCount()
93 {
94 return getDataModel().getRowCount();
95 }
96
97 public Object getRowData()
98 {
99 return getDataModel().getRowData();
100 }
101
102 public int getRowIndex()
103 {
104 return _rowIndex;
105 }
106
107
108
109
110 public String getClientId(FacesContext context)
111 {
112 String clientId = HtmlComponentUtils.getClientId(this, getRenderer(context), context);
113 if (clientId == null)
114 {
115 clientId = super.getClientId(context);
116 }
117 int rowIndex = getRowIndex();
118 if (rowIndex == -1)
119 {
120 return clientId;
121 }
122
123
124 int index = clientId.lastIndexOf(NamingContainer.SEPARATOR_CHAR);
125 if(index != -1)
126 {
127 String rowIndexString = clientId.substring(index + 1);
128 try
129 {
130 if(Integer.parseInt(rowIndexString) == rowIndex)
131 {
132 return clientId.substring(0, index+1) + getDerivedSubClientId();
133 }
134 }
135 catch(NumberFormatException e)
136 {
137 return clientId + NamingContainer.SEPARATOR_CHAR + getDerivedSubClientId();
138 }
139 }
140 return clientId + NamingContainer.SEPARATOR_CHAR + getDerivedSubClientId();
141 }
142
143
144
145
146 public void processUpdates(FacesContext context)
147 {
148 super.processUpdates(context);
149
150 if (context.getRenderResponse())
151 {
152 _isValidChilds = false;
153 }
154 }
155
156
157
158
159
160
161
162
163 protected void checkUpdateModelError(FacesContext context)
164 {
165 if (context.getRenderResponse())
166 {
167 _isValidChilds = false;
168 }
169 }
170
171
172
173
174 public void processValidators(FacesContext context)
175 {
176 super.processValidators(context);
177
178 if (context.getRenderResponse())
179 {
180 _isValidChilds = false;
181 }
182 }
183
184
185
186
187 public void encodeBegin(FacesContext context) throws IOException
188 {
189 _initialDescendantComponentState = null;
190 if (_isValidChilds && !hasErrorMessages(context))
191 {
192
193 _dataModelMap.clear();
194 if (!isPreserveRowStates())
195 {
196 _rowStates.clear();
197 }
198 }
199 super.encodeBegin(context);
200 }
201
202 public void setPreserveRowStates(boolean preserveRowStates)
203 {
204 _preserveRowStates = Boolean.valueOf(preserveRowStates);
205 }
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222 public boolean isPreserveRowStates()
223 {
224 if (_preserveRowStates != null)
225 return _preserveRowStates.booleanValue();
226 ValueBinding vb = getValueBinding("preserveRowStates");
227 Boolean v = vb != null ? (Boolean) vb.getValue(getFacesContext()) : null;
228 return v != null ? v.booleanValue() : DEFAULT_PRESERVEROWSTATES;
229 }
230
231 protected boolean hasErrorMessages(FacesContext context)
232 {
233 for(Iterator iter = context.getMessages(); iter.hasNext();)
234 {
235 FacesMessage message = (FacesMessage) iter.next();
236 if(FacesMessage.SEVERITY_ERROR.compareTo(message.getSeverity()) <= 0)
237 {
238 return true;
239 }
240 }
241 return false;
242 }
243
244
245
246
247 public void encodeEnd(FacesContext context) throws IOException
248 {
249 setRowIndex(-1);
250 super.encodeEnd(context);
251 }
252
253 public void setRowIndex(int rowIndex)
254 {
255 if (rowIndex < -1)
256 {
257 throw new IllegalArgumentException("rowIndex is less than -1");
258 }
259
260 if (_rowIndex == rowIndex)
261 {
262 return;
263 }
264
265 FacesContext facesContext = getFacesContext();
266
267 if (_rowIndex == -1)
268 {
269 if (_initialDescendantComponentState == null)
270 {
271 _initialDescendantComponentState = saveDescendantComponentStates();
272 }
273 }
274 else
275 {
276 _rowStates.put(getClientId(facesContext),
277 saveDescendantComponentStates());
278 }
279
280 _rowIndex = rowIndex;
281
282 DataModel dataModel = getDataModel();
283 dataModel.setRowIndex(rowIndex);
284
285 String var = getVar();
286 if (rowIndex == -1)
287 {
288 if (var != null)
289 {
290 facesContext.getExternalContext().getRequestMap().remove(var);
291 }
292 }
293 else
294 {
295 if (var != null)
296 {
297 if (isRowAvailable())
298 {
299 Object rowData = dataModel.getRowData();
300 facesContext.getExternalContext().getRequestMap().put(var,
301 rowData);
302 }
303 else
304 {
305 facesContext.getExternalContext().getRequestMap().remove(
306 var);
307 }
308 }
309 }
310
311 if (_rowIndex == -1)
312 {
313 restoreDescendantComponentStates(_initialDescendantComponentState);
314 }
315 else
316 {
317 Object rowState = _rowStates.get(getClientId(facesContext));
318 if (rowState == null)
319 {
320 restoreDescendantComponentStates(_initialDescendantComponentState);
321 }
322 else
323 {
324 restoreDescendantComponentStates(rowState);
325 }
326 }
327 }
328
329 protected void restoreDescendantComponentStates(Object state)
330 {
331 restoreDescendantComponentStates(getChildren().iterator(), state, false);
332 }
333
334 protected void restoreDescendantComponentStates(Iterator childIterator,
335 Object state, boolean restoreChildFacets)
336 {
337 Iterator descendantStateIterator = null;
338 while (childIterator.hasNext())
339 {
340 if (descendantStateIterator == null && state != null)
341 {
342 descendantStateIterator = ((Collection) state).iterator();
343 }
344 UIComponent component = (UIComponent) childIterator.next();
345
346 component.setId(component.getId());
347 if(!component.isTransient())
348 {
349 Object childState = null;
350 Object descendantState = null;
351 if (descendantStateIterator != null
352 && descendantStateIterator.hasNext())
353 {
354 Object[] object = (Object[]) descendantStateIterator.next();
355 childState = object[0];
356 descendantState = object[1];
357 }
358 if (childState != null && component instanceof EditableValueHolder)
359 {
360 ((EditableValueHolderState) childState)
361 .restoreState((EditableValueHolder) component);
362 }
363 Iterator childsIterator;
364 if (restoreChildFacets)
365 {
366 childsIterator = component.getFacetsAndChildren();
367 }
368 else
369 {
370 childsIterator = component.getChildren().iterator();
371 }
372 restoreDescendantComponentStates(childsIterator, descendantState,
373 true);
374 }
375 }
376 }
377
378 protected Object saveDescendantComponentStates()
379 {
380 return saveDescendantComponentStates(getChildren().iterator(), false);
381 }
382
383 protected Object saveDescendantComponentStates(Iterator childIterator,
384 boolean saveChildFacets)
385 {
386 Collection childStates = null;
387 while (childIterator.hasNext())
388 {
389 if (childStates == null)
390 {
391 childStates = new ArrayList();
392 }
393 UIComponent child = (UIComponent) childIterator.next();
394 if(!child.isTransient())
395 {
396 Iterator childsIterator;
397 if (saveChildFacets)
398 {
399 childsIterator = child.getFacetsAndChildren();
400 }
401 else
402 {
403 childsIterator = child.getChildren().iterator();
404 }
405 Object descendantState = saveDescendantComponentStates(
406 childsIterator, true);
407 Object state = null;
408 if (child instanceof EditableValueHolder)
409 {
410 state = new EditableValueHolderState(
411 (EditableValueHolder) child);
412 }
413 childStates.add(new Object[] { state, descendantState });
414 }
415 }
416 return childStates;
417 }
418
419 public void setValueBinding(String name, ValueBinding binding)
420 {
421 if (name == null)
422 {
423 throw new NullPointerException("name");
424 }
425 else if (name.equals("value"))
426 {
427 _dataModelMap.clear();
428 }
429 else if (name.equals("var") || name.equals("rowIndex"))
430 {
431 throw new IllegalArgumentException(
432 "You can never set the 'rowIndex' or the 'var' attribute as a value-binding. Set the property directly instead. Name " + name);
433 }
434 super.setValueBinding(name, binding);
435 }
436
437
438
439
440 public void setValue(Object value)
441 {
442 super.setValue(value);
443 _dataModelMap.clear();
444 _rowStates.clear();
445 _isValidChilds = true;
446 }
447
448 protected DataModel getDataModel()
449 {
450 DataModel dataModel = null;
451 String clientID = "";
452
453 UIComponent parent = getParent();
454 if (parent != null)
455 {
456 clientID = parent.getClientId(getFacesContext());
457 }
458 dataModel = (DataModel) _dataModelMap.get(clientID);
459 if (dataModel == null)
460 {
461 dataModel = createDataModel();
462 _dataModelMap.put(clientID, dataModel);
463 }
464
465 return dataModel;
466 }
467
468 protected void setDataModel(DataModel datamodel)
469 {
470 UIComponent parent = getParent();
471 String clientID = "";
472 if(parent != null)
473 {
474 clientID = parent.getClientId(getFacesContext());
475 }
476 _dataModelMap.put(clientID, datamodel);
477 }
478
479
480
481
482 protected DataModel createDataModel()
483 {
484 Object value = getValue();
485 if (value == null)
486 {
487 return EMPTY_DATA_MODEL;
488 }
489 else if (value instanceof DataModel)
490 {
491 return (DataModel) value;
492 }
493 else if (value instanceof List)
494 {
495 return new ListDataModel((List) value);
496 }
497
498 else if (value instanceof Collection)
499 {
500 return new ListDataModel(new ArrayList((Collection) value));
501 }
502 else if (OBJECT_ARRAY_CLASS.isAssignableFrom(value.getClass()))
503 {
504 return new ArrayDataModel((Object[]) value);
505 }
506 else if (value instanceof ResultSet)
507 {
508 return new ResultSetDataModel((ResultSet) value);
509 }
510 else if (value instanceof Result)
511 {
512 return new ResultDataModel((Result) value);
513 }
514 else
515 {
516 return new ScalarDataModel(value);
517 }
518 }
519
520 public Object saveState(FacesContext context)
521 {
522 Object[] values = new Object[5];
523 values[0] = super.saveState(context);
524 values[1] = _preserveRowStates;
525 values[2] = _forceId;
526 values[3] = _forceIdIndex;
527 values[4] = _derivedRowKeyPrefix;
528 return values;
529 }
530
531 public void restoreState(FacesContext context, Object state)
532 {
533 Object[] values = (Object[])state;
534 super.restoreState(context, values[0]);
535 _preserveRowStates = (Boolean) values[1];
536 _forceId = (Boolean) values[2];
537 _forceIdIndex = (Boolean) values[3];
538 _derivedRowKeyPrefix = (String) values[4];
539 }
540
541 private static final DataModel EMPTY_DATA_MODEL = new _SerializableDataModel()
542 {
543 public boolean isRowAvailable()
544 {
545 return false;
546 }
547
548 public int getRowCount()
549 {
550 return 0;
551 }
552
553 public Object getRowData()
554 {
555 throw new IllegalArgumentException();
556 }
557
558 public int getRowIndex()
559 {
560 return -1;
561 }
562
563 public void setRowIndex(int i)
564 {
565 if (i < -1)
566 throw new IndexOutOfBoundsException("Index < 0 : " + i);
567 }
568
569 public Object getWrappedData()
570 {
571 return null;
572 }
573
574 public void setWrappedData(Object obj)
575 {
576 if (obj == null)
577 return;
578 throw new UnsupportedOperationException(this.getClass().getName()
579 + " UnsupportedOperationException");
580 }
581 };
582
583 private class EditableValueHolderState
584 {
585 private final Object _value;
586 private final boolean _localValueSet;
587 private final boolean _valid;
588 private final Object _submittedValue;
589
590 public EditableValueHolderState(EditableValueHolder evh)
591 {
592 _value = evh.getLocalValue();
593 _localValueSet = evh.isLocalValueSet();
594 _valid = evh.isValid();
595 _submittedValue = evh.getSubmittedValue();
596 }
597
598 public void restoreState(EditableValueHolder evh)
599 {
600 evh.setValue(_value);
601 evh.setLocalValueSet(_localValueSet);
602 evh.setValid(_valid);
603 evh.setSubmittedValue(_submittedValue);
604 }
605 }
606
607
608 private Boolean _forceId = Boolean.valueOf(false);
609
610
611
612
613
614
615
616
617
618
619 public boolean isForceId()
620 {
621 return _forceId.booleanValue();
622 }
623
624 public void setForceId(boolean forceId)
625 {
626 this._forceId = Boolean.valueOf(forceId);
627 }
628
629 private Boolean _forceIdIndex = Boolean.valueOf(true);
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644 public boolean isForceIdIndex()
645 {
646 return _forceIdIndex.booleanValue();
647 }
648
649 public void setForceIdIndex(boolean forceIdIndex)
650 {
651 this._forceIdIndex = Boolean.valueOf(forceIdIndex);
652 }
653
654 private static boolean booleanFromObject(Object obj, boolean defaultValue)
655 {
656 if(obj instanceof Boolean)
657 {
658 return ((Boolean) obj).booleanValue();
659 }
660 else if(obj instanceof String)
661 {
662 return Boolean.valueOf(((String) obj)).booleanValue();
663 }
664
665 return defaultValue;
666 }
667
668
669
670
671 public void clearRowStates()
672 {
673 _rowStates.clear();
674 }
675
676
677
678
679
680 public void deleteRowStateForRow(int deletedIndex)
681 {
682
683 int savedRowIndex = getRowIndex();
684
685 FacesContext facesContext = getFacesContext();
686 setRowIndex(deletedIndex);
687 String currentRowStateKey = getClientId(facesContext);
688
689 Object rowKey = getRowKey();
690 if (rowKey != null)
691 {
692 setRowIndex(deletedIndex);
693 _rowStates.remove(currentRowStateKey);
694 setRowIndex(savedRowIndex);
695 }
696 else
697 {
698
699 int rowCount = getRowCount();
700 for (int index = deletedIndex + 1; index < rowCount; ++index)
701 {
702 setRowIndex(index);
703 String nextRowStateKey = getClientId(facesContext);
704
705 Object nextRowState = _rowStates.get(nextRowStateKey);
706 if (nextRowState == null)
707 {
708 _rowStates.remove(currentRowStateKey);
709 }
710 else
711 {
712 _rowStates.put(currentRowStateKey, nextRowState);
713 }
714 currentRowStateKey = nextRowStateKey;
715 }
716
717
718 _rowStates.remove(currentRowStateKey);
719
720
721 setRowIndex(savedRowIndex);
722 }
723 }
724
725
726
727
728
729
730
731
732
733
734
735
736 public Object getRowKey()
737 {
738
739
740
741
742 ValueBinding vb = getValueBinding("rowKey");
743 if (vb != null)
744 {
745 Object value = vb.getValue(getFacesContext());
746 if (value == null)
747 {
748 return null;
749 }
750 else
751 {
752 return (Object) value;
753 }
754 }
755 return null;
756 }
757
758 public void setRowKey(Object rowKey)
759 {
760
761 }
762
763 private String _derivedRowKeyPrefix;
764
765
766
767
768
769
770
771
772
773 public String getDerivedRowKeyPrefix()
774 {
775 if (_derivedRowKeyPrefix != null)
776 {
777 return _derivedRowKeyPrefix;
778 }
779 ValueBinding vb = getValueBinding("derivedRowKeyPrefix");
780 if (vb != null)
781 {
782 Object value = vb.getValue(getFacesContext());
783 if (value == null)
784 {
785 return UNIQUE_ROW_ID_PREFIX;
786 }
787 else
788 {
789 return (String) value.toString();
790 }
791 }
792 return UNIQUE_ROW_ID_PREFIX;
793 }
794
795 public void setDerivedRowKeyPrefix(String derivedRowKeyPrefix)
796 {
797 this._derivedRowKeyPrefix = derivedRowKeyPrefix;
798 }
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816 protected String getDerivedSubClientId()
817 {
818 Object key = getRowKey();
819 if (key == null)
820 {
821 return _SubIdConverter.encode(Integer.toString(getRowIndex()));
822 }
823 else
824 {
825 return getDerivedRowKeyPrefix() + _SubIdConverter.encode(key.toString());
826 }
827 }
828
829 }