KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > myfaces > component > html > ext > HtmlDataTableHack


1 package org.apache.myfaces.component.html.ext;
2
3 import javax.faces.component.EditableValueHolder;
4 import javax.faces.component.UIComponent;
5 import javax.faces.component.UIData;
6 import javax.faces.context.FacesContext;
7 import javax.faces.el.ValueBinding;
8 import javax.faces.model.*;
9 import javax.servlet.jsp.jstl.sql.Result;
10 import java.io.Serializable JavaDoc;
11 import java.sql.ResultSet JavaDoc;
12 import java.util.ArrayList JavaDoc;
13 import java.util.HashMap JavaDoc;
14 import java.util.Iterator JavaDoc;
15 import java.util.List JavaDoc;
16
17 /**
18  * Reimplement all UIData functionality to be able to have (protected) access
19  * the internal DataModel.
20  *
21  * @author Manfred Geiler (latest modification by $Author: mmarinschek $)
22  * @version $Revision: 1.5 $ $Date: 2005/01/26 17:48:19 $
23  */

24 abstract class HtmlDataTableHack
25         extends javax.faces.component.html.HtmlDataTable
26 {
27     protected DataModel _dataModel = null;
28     protected HashMap JavaDoc _dataModelMap = null;
29
30     //init to false, so that no descendant states are saved for a newly created UIData
31
transient protected boolean _saveDescendantStates = false;
32
33
34     // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
35
// Every field and method from here is identical to UIData !!!!!!!!!
36

37     private static final Class JavaDoc OBJECT_ARRAY_CLASS = (new Object JavaDoc[0]).getClass();
38
39     private static final Integer JavaDoc INTEGER_MINUS1 = new Integer JavaDoc(-1);
40
41     private int _rowIndex = -1;
42     private Object JavaDoc[] _descendantStates;
43     private int _descendantEditableValueHolderCount = -1;
44
45     private Boolean JavaDoc _isEmbeddedUIData = null;
46     private UIData _embeddingUIData = null;
47
48
49     public boolean isRowAvailable()
50     {
51         return getDataModel().isRowAvailable();
52     }
53
54     public int getRowCount()
55     {
56         return getDataModel().getRowCount();
57     }
58
59     public Object JavaDoc getRowData()
60     {
61         return getDataModel().getRowData();
62     }
63
64     public int getRowIndex()
65     {
66         return _rowIndex;
67     }
68
69     public void setRowIndex(int rowIndex)
70     {
71         saveDescendantComponentStates();
72
73         _rowIndex = rowIndex;
74
75         DataModel dataModel = getDataModel();
76         dataModel.setRowIndex(rowIndex);
77
78         String JavaDoc var = getVar();
79         if (rowIndex == -1)
80         {
81             if (var != null)
82             {
83                 getFacesContext().getExternalContext().getRequestMap().remove(var);
84             }
85         }
86         else
87         {
88             if (var != null)
89             {
90                 if (isRowAvailable())
91                 {
92                     Object JavaDoc rowData = dataModel.getRowData();
93                     getFacesContext().getExternalContext().getRequestMap().put(var, rowData);
94                 }
95                 else
96                 {
97                     getFacesContext().getExternalContext().getRequestMap().remove(var);
98                 }
99             }
100         }
101
102         restoreDescendantComponentStates();
103     }
104
105
106     private int getDescendantStatesRowIndex()
107     {
108         int rowIndex = getRowIndex();
109         if (rowIndex == -1)
110         {
111             return 0;
112         }
113         else
114         {
115             return rowIndex - getFirst() + 1;
116         }
117     }
118
119     /**
120      * The descendant Component states algorithm we implement here is pretty fast
121      * but does not support modification of the components tree during the lifecycle.
122      * TODO: should we offer an alternative implementation with a clientId based Map ?
123      */

124     private void saveDescendantComponentStates()
125     {
126         if (_descendantEditableValueHolderCount == -1)
127         {
128             //This is the first time we save the descendant components state
129
refreshDescendantDataStates();
130         }
131         else if (_descendantEditableValueHolderCount == 0)
132         {
133             //There are no EditableValueHolder children
134
return;
135         }
136         else
137         {
138             int rowIndex = getDescendantStatesRowIndex();
139             EditableValueHolderState[] rowState;
140             // make sure that the underlying data did not change size
141
// (i.e. someone added a row to the DataModel)
142
// BUG: #925693
143
if(rowIndex < _descendantStates.length) {
144                 rowState = (EditableValueHolderState[])_descendantStates[rowIndex];
145             } else {
146                 // changed size during the lifecycle - should refresh
147
refreshDescendantDataStates();
148                 rowState = (EditableValueHolderState[])_descendantStates[rowIndex];
149             }
150             if (rowState == null)
151             {
152                 rowState = new EditableValueHolderState[_descendantEditableValueHolderCount];
153                 _descendantStates[rowIndex] = rowState;
154             }
155             saveDescendantComponentStates(this, rowState, 0, 0);
156         }
157     }
158
159     private void refreshDescendantDataStates() {
160         List JavaDoc list = new ArrayList JavaDoc();
161         saveDescendantComponentStates(this, list,0);
162         _descendantEditableValueHolderCount = list.size();
163         if (_descendantEditableValueHolderCount > 0)
164         {
165             EditableValueHolderState[] rowState
166                     = (EditableValueHolderState[])list.toArray(new EditableValueHolderState[list.size()]);
167             int rows = getRows();
168             if (rows <= 0)
169             {
170                 rows = getRowCount() - getFirst();
171             }
172             _descendantStates = new Object JavaDoc[rows + 1];
173             int rowIndex = getDescendantStatesRowIndex();
174             _descendantStates[rowIndex] = rowState;
175         }
176     }
177
178     private static void saveDescendantComponentStates(UIComponent component, List JavaDoc list, int level)
179     {
180         for (Iterator JavaDoc it=getChildrenAndOptionalFacetsIterator(level, component); it.hasNext();)
181         {
182             UIComponent child = (UIComponent)it.next();
183             if (child instanceof EditableValueHolder)
184             {
185                 list.add(new EditableValueHolderState((EditableValueHolder)child));
186             }
187             saveDescendantComponentStates(child, list, level+1);
188         }
189     }
190
191     private static int saveDescendantComponentStates(UIComponent component,
192                                                      EditableValueHolderState[] states,
193                                                      int counter, int level)
194     {
195         for (Iterator JavaDoc it=getChildrenAndOptionalFacetsIterator(level, component); it.hasNext();)
196         {
197             UIComponent child = (UIComponent)it.next();
198             if (child instanceof EditableValueHolder)
199             {
200                 states[counter++] = new EditableValueHolderState((EditableValueHolder)child);
201             }
202             counter = saveDescendantComponentStates(child, states, counter, level+1);
203         }
204         return counter;
205     }
206
207     private void restoreDescendantComponentStates()
208     {
209         if (_descendantEditableValueHolderCount == -1)
210         {
211             throw new IllegalStateException JavaDoc("saveDescendantComponentStates not called yet?");
212         }
213         else if (_descendantEditableValueHolderCount > 0)
214         {
215             // There is at least one descendant component to be restored
216

217             // Get zero-based index (instead of -1 based UIData zeroBasedRowIdx):
218
int zeroBasedRowIdx = getDescendantStatesRowIndex();
219
220             // Is there a reason to restore the state of a new descendant?
221
// BUG: 925693
222
// manolito: Yes, descendants for a row not yet saved, must be
223
// reset to initial row state!
224
int stateRowsCount = _descendantStates.length;
225
226             EditableValueHolderState[] initialStates = null;
227             if (stateRowsCount > 0)
228             {
229                 // No state saved yet for this row, let's restore initial values:
230
initialStates = (EditableValueHolderState[]) _descendantStates[0];
231             }
232
233             if (zeroBasedRowIdx < stateRowsCount)
234             {
235                 // There is a saved state for this row, so restore these values:
236
EditableValueHolderState[] rowState =
237                     (EditableValueHolderState[]) _descendantStates[zeroBasedRowIdx];
238                 restoreDescendantComponentStates(this, rowState, initialStates, 0,0);
239             }
240             else
241             {
242                 // No state saved yet for this row, let's restore initial values:
243
restoreDescendantComponentStates(this, initialStates, initialStates, 0,0);
244             }
245         }
246         else
247         {
248             // There are no states to restore, so only recurse to set the
249
// right clientIds for all descendants
250
restoreDescendantComponentStates(this, null, null, 0,0);
251         }
252     }
253
254     private static int restoreDescendantComponentStates(UIComponent component,
255                                                         EditableValueHolderState[] states,
256                                                         EditableValueHolderState[] initialStates,
257                                                         int counter, int level)
258     {
259         for (Iterator JavaDoc it=getChildrenAndOptionalFacetsIterator(level, component); it.hasNext();)
260         {
261             UIComponent child = (UIComponent)it.next();
262             //clear this descendant's clientId:
263
child.setId(child.getId()); //HACK: This assumes that setId always clears the cached clientId. Can we be sure?
264
if (child instanceof EditableValueHolder)
265             {
266                 if (states != null)
267                 {
268                     states[counter].restore((EditableValueHolder)child);
269                 }
270                 else if (initialStates != null)
271                 {
272                     initialStates[counter].restore((EditableValueHolder)child);
273                 }
274                 else
275                 {
276                     // No state saved yet and no initial state !?
277
// Should never be possible, but let's reset the component
278
// state to null values
279
((EditableValueHolder)child).setValue(null);
280                     ((EditableValueHolder)child).setLocalValueSet(false);
281                     ((EditableValueHolder)child).setValid(true);
282                     ((EditableValueHolder)child).setSubmittedValue(null);
283                 }
284                 counter++;
285             }
286             counter = restoreDescendantComponentStates(child, states, initialStates, counter,level+1);
287         }
288         return counter;
289     }
290
291     private static Iterator JavaDoc getChildrenAndOptionalFacetsIterator(int level, UIComponent component)
292     {
293         Iterator JavaDoc it;
294
295         if(level>1)
296         {
297             it = component.getFacetsAndChildren();
298         }
299         else
300         {
301             it = component.getChildren().iterator();
302         }
303         return it;
304     }
305
306
307     public void setValueBinding(String JavaDoc name,
308                                 ValueBinding binding)
309     {
310         if (name == null)
311         {
312             throw new NullPointerException JavaDoc("name");
313         }
314         else if (name.equals("value"))
315         {
316             _dataModel = null;
317         }
318         else if (name.equals("var") || name.equals("rowIndex"))
319         {
320             throw new IllegalArgumentException JavaDoc("name " + name);
321         }
322         super.setValueBinding(name, binding);
323     }
324
325
326     private DataModel getDataModel()
327     {
328         UIData embeddingUIData = getEmbeddingUIData();
329         if (embeddingUIData != null)
330         {
331             //This UIData is nested in another UIData, so we must not
332
//do simple caching of the current DataModel. We must associate
333
//the DataModel that we want to cache with the clientId of the
334
//embedding UIData. This clientId will be different for every
335
//row of the embedding UIData.
336
if (_dataModelMap == null)
337             {
338                 _dataModelMap = new HashMap JavaDoc();
339             }
340             String JavaDoc embeddingClientId = embeddingUIData.getClientId(FacesContext.getCurrentInstance());
341             DataModel dataModel = (DataModel) _dataModelMap.get(embeddingClientId);
342             if (dataModel == null)
343             {
344                 dataModel = createDataModel();
345                 _dataModelMap.put(embeddingClientId, dataModel);
346             }
347             return dataModel;
348         }
349         else
350         {
351             //This UIData is not nested within another UIData. So there
352
//is no need for the DataModel Map.
353
if (_dataModel == null)
354             {
355                 _dataModel = createDataModel();
356             }
357             return _dataModel;
358         }
359     }
360
361     /**
362      * Creates a new DataModel around the current value.
363      */

364     private DataModel createDataModel()
365     {
366         Object JavaDoc value = getValue();
367         if (value == null)
368         {
369             return EMPTY_DATA_MODEL;
370         }
371         else if (value instanceof DataModel)
372         {
373             return (DataModel)value;
374         }
375         else if (value instanceof List JavaDoc)
376         {
377             return new ListDataModel((List JavaDoc)value);
378         }
379         else if (OBJECT_ARRAY_CLASS.isAssignableFrom(value.getClass()))
380         {
381             return new ArrayDataModel((Object JavaDoc[])value);
382         }
383         else if (value instanceof ResultSet JavaDoc)
384         {
385             return new ResultSetDataModel((ResultSet JavaDoc)value);
386         }
387         else if (value instanceof Result)
388         {
389             return new ResultDataModel((Result)value);
390         }
391         else
392         {
393             return new ScalarDataModel(value);
394         }
395     }
396
397     /**
398      * Looks for an embedding UIData component
399      * @return the embedding UIData or null
400      */

401     private UIData getEmbeddingUIData()
402     {
403         if (_isEmbeddedUIData == null)
404         {
405             UIComponent findParentUIData = getParent();
406             while (findParentUIData != null &&
407                    !(findParentUIData instanceof UIData))
408             {
409                 findParentUIData = findParentUIData.getParent();
410             }
411             if (findParentUIData != null)
412             {
413                 _embeddingUIData = (UIData)findParentUIData;
414                 _isEmbeddedUIData = Boolean.TRUE;
415             }
416             else
417             {
418                 _isEmbeddedUIData = Boolean.FALSE;
419             }
420         }
421
422         if (_isEmbeddedUIData.booleanValue())
423         {
424             return _embeddingUIData;
425         }
426         else
427         {
428             return null;
429         }
430     }
431
432
433     private static final DataModel EMPTY_DATA_MODEL = new DataModel()
434     {
435         public boolean isRowAvailable()
436         {
437             return false;
438         }
439
440         public int getRowCount()
441         {
442             return 0;
443         }
444
445         public Object JavaDoc getRowData()
446         {
447             throw new IllegalArgumentException JavaDoc();
448         }
449
450         public int getRowIndex()
451         {
452             return -1;
453         }
454
455         public void setRowIndex(int i)
456         {
457             if (i < -1) throw new IllegalArgumentException JavaDoc();
458         }
459
460         public Object JavaDoc getWrappedData()
461         {
462             return null;
463         }
464
465         public void setWrappedData(Object JavaDoc obj)
466         {
467             if (obj == null) return; //Clearing is allowed
468
throw new UnsupportedOperationException JavaDoc(this.getClass().getName() + " UnsupportedOperationException");
469         }
470     };
471
472
473     private static class EditableValueHolderState
474             implements Serializable JavaDoc
475     {
476         private Object JavaDoc _localValue;
477         private boolean _localValueSet;
478         private boolean _valid;
479         private Object JavaDoc _submittedValue;
480
481         public EditableValueHolderState(EditableValueHolder vh)
482         {
483             _localValue = vh.getLocalValue();
484             _localValueSet = vh.isLocalValueSet();
485             _valid = vh.isValid();
486             _submittedValue = vh.getSubmittedValue();
487         }
488
489         public void restore(EditableValueHolder vh)
490         {
491             vh.setValue(_localValue);
492             vh.setLocalValueSet(_localValueSet);
493             vh.setValid(_valid);
494             vh.setSubmittedValue(_submittedValue);
495         }
496     }
497
498
499     public Object JavaDoc saveState(FacesContext context)
500     {
501         Object JavaDoc values[] = new Object JavaDoc[7];
502         values[0] = super.saveState(context);
503         values[1] = _saveDescendantStates ? _descendantStates : null;
504         values[2] = _saveDescendantStates ? new Integer JavaDoc(_descendantEditableValueHolderCount) : INTEGER_MINUS1;
505         return values;
506     }
507
508     public void restoreState(FacesContext context, Object JavaDoc state)
509     {
510         Object JavaDoc values[] = (Object JavaDoc[])state;
511         super.restoreState(context, values[0]);
512         _descendantStates = (Object JavaDoc[])values[1];
513         _descendantEditableValueHolderCount = ((Integer JavaDoc)values[2]).intValue();
514     }
515
516 }
517
Popular Tags