KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tapestry > contrib > table > components > TableView


1 // Copyright 2004, 2005 The Apache Software Foundation
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15 package org.apache.tapestry.contrib.table.components;
16
17 import java.io.Serializable JavaDoc;
18 import java.util.ArrayList JavaDoc;
19 import java.util.Collection JavaDoc;
20 import java.util.Iterator JavaDoc;
21 import java.util.List JavaDoc;
22
23 import org.apache.hivemind.ApplicationRuntimeException;
24 import org.apache.tapestry.BaseComponent;
25 import org.apache.tapestry.IComponent;
26 import org.apache.tapestry.IMarkupWriter;
27 import org.apache.tapestry.IRequestCycle;
28 import org.apache.tapestry.contrib.table.model.IAdvancedTableColumnSource;
29 import org.apache.tapestry.contrib.table.model.IBasicTableModel;
30 import org.apache.tapestry.contrib.table.model.ITableColumn;
31 import org.apache.tapestry.contrib.table.model.ITableColumnModel;
32 import org.apache.tapestry.contrib.table.model.ITableDataModel;
33 import org.apache.tapestry.contrib.table.model.ITableModel;
34 import org.apache.tapestry.contrib.table.model.ITableModelSource;
35 import org.apache.tapestry.contrib.table.model.ITablePagingState;
36 import org.apache.tapestry.contrib.table.model.ITableSessionStateManager;
37 import org.apache.tapestry.contrib.table.model.ITableSessionStoreManager;
38 import org.apache.tapestry.contrib.table.model.common.BasicTableModelWrap;
39 import org.apache.tapestry.contrib.table.model.simple.SimpleListTableDataModel;
40 import org.apache.tapestry.contrib.table.model.simple.SimpleTableColumnModel;
41 import org.apache.tapestry.contrib.table.model.simple.SimpleTableModel;
42 import org.apache.tapestry.contrib.table.model.simple.SimpleTableState;
43 import org.apache.tapestry.event.PageBeginRenderListener;
44 import org.apache.tapestry.event.PageDetachListener;
45 import org.apache.tapestry.event.PageEvent;
46
47 /**
48  * A low level Table component that wraps all other low level Table components. This component
49  * carries the {@link org.apache.tapestry.contrib.table.model.ITableModel}that is used by the other
50  * Table components. Please see the documentation of
51  * {@link org.apache.tapestry.contrib.table.model.ITableModel}if you need to know more about how a
52  * table is represented.
53  * <p>
54  * This component also handles the saving of the state of the model using an
55  * {@link org.apache.tapestry.contrib.table.model.ITableSessionStateManager}to determine what part
56  * of the model is to be saved and an
57  * {@link org.apache.tapestry.contrib.table.model.ITableSessionStoreManager}to determine how to
58  * save it.
59  * <p>
60  * Upon the beginning of a new request cycle when the table model is first needed, the model is
61  * obtained using the following process:
62  * <ul>
63  * <li>The persistent state of the table is loaded. If the tableSessionStoreManager binding has not
64  * been bound, the state is loaded from a persistent property within the component (it is null at
65  * the beginning). Otherwise the supplied
66  * {@link org.apache.tapestry.contrib.table.model.ITableSessionStoreManager}is used to load the
67  * persistent state.
68  * <li>The table model is recreated using the
69  * {@link org.apache.tapestry.contrib.table.model.ITableSessionStateManager}that could be supplied
70  * using the tableSessionStateManager binding (but has a default value and is therefore not
71  * required).
72  * <li>If the {@link org.apache.tapestry.contrib.table.model.ITableSessionStateManager}returns
73  * null, then a table model is taken from the tableModel binding. Thus, if the
74  * {@link org.apache.tapestry.contrib.table.model.common.NullTableSessionStateManager}is used, the
75  * table model would be taken from the tableModel binding every time.
76  * </ul>
77  * Just before the rendering phase the persistent state of the model is saved in the session. This
78  * process occurs in reverse:
79  * <ul>
80  * <li>The persistent state of the model is taken via the
81  * {@link org.apache.tapestry.contrib.table.model.ITableSessionStateManager}.
82  * <li>If the tableSessionStoreManager binding has not been bound, the persistent state is saved as
83  * a persistent page property. Otherwise the supplied
84  * {@link org.apache.tapestry.contrib.table.model.ITableSessionStoreManager}is used to save the
85  * persistent state. Use of the
86  * {@link org.apache.tapestry.contrib.table.model.ITableSessionStoreManager}is usually necessary
87  * when tables with the same model have to be used across multiple pages, and hence the state has to
88  * be saved in the Visit, rather than in a persistent component property.
89  * </ul>
90  * <p>
91  * <p>
92  * Please see the Component Reference for details on how to use this component. [ <a
93  * HREF="../../../../../../../ComponentReference/contrib.TableView.html">Component Reference </a>]
94  *
95  * @author mindbridge
96  */

97 public abstract class TableView extends BaseComponent implements PageDetachListener,
98         PageBeginRenderListener, ITableModelSource
99 {
100     /** @since 4.0 */
101     public abstract TableColumnModelSource getModelSource();
102
103     /** @since 4.0 */
104     public abstract IAdvancedTableColumnSource getColumnSource();
105     
106     // Component properties
107
private ITableSessionStateManager m_objDefaultSessionStateManager = null;
108
109     private ITableColumnModel m_objColumnModel = null;
110
111     // Transient objects
112
private ITableModel m_objTableModel;
113
114     private ITableModel m_objCachedTableModelValue;
115
116     // enhanced parameter methods
117
public abstract ITableModel getTableModelValue();
118
119     public abstract Object JavaDoc getSource();
120
121     public abstract Object JavaDoc getColumns();
122
123     public abstract int getInitialPage();
124
125     public abstract String JavaDoc getInitialSortColumn();
126
127     public abstract boolean getInitialSortOrder();
128
129     public abstract ITableSessionStateManager getTableSessionStateManager();
130
131     public abstract ITableSessionStoreManager getTableSessionStoreManager();
132
133     public abstract IComponent getColumnSettingsContainer();
134
135     public abstract int getPageSize();
136
137     public abstract String JavaDoc getPersist();
138
139     // enhanced property methods
140
public abstract Serializable JavaDoc getSessionState();
141
142     public abstract void setSessionState(Serializable JavaDoc sessionState);
143
144     public abstract Serializable JavaDoc getClientState();
145
146     public abstract void setClientState(Serializable JavaDoc sessionState);
147
148     public abstract Serializable JavaDoc getClientAppState();
149
150     public abstract void setClientAppState(Serializable JavaDoc sessionState);
151
152     /**
153      * The component constructor. Invokes the component member initializations.
154      */

155     public TableView()
156     {
157         initialize();
158     }
159
160     /**
161      * Invokes the component member initializations.
162      *
163      * @see org.apache.tapestry.event.PageDetachListener#pageDetached(PageEvent)
164      */

165     public void pageDetached(PageEvent objEvent)
166     {
167         initialize();
168     }
169
170     /**
171      * Initialize the component member variables.
172      */

173     private void initialize()
174     {
175         m_objTableModel = null;
176         m_objCachedTableModelValue = null;
177     }
178
179     /**
180      * Resets the table by removing any stored table state. This means that the current column to
181      * sort on and the current page will be forgotten and all data will be reloaded.
182      */

183     public void reset()
184     {
185         initialize();
186         storeSessionState(null);
187     }
188
189     public ITableModel getCachedTableModelValue()
190     {
191         if (m_objCachedTableModelValue == null)
192             m_objCachedTableModelValue = getTableModelValue();
193         return m_objCachedTableModelValue;
194     }
195
196     /**
197      * Returns the tableModel.
198      *
199      * @return ITableModel the table model used by the table components
200      */

201     public ITableModel getTableModel()
202     {
203         // if null, first try to recreate the model from the session state
204
if (m_objTableModel == null)
205         {
206             Serializable JavaDoc objState = loadSessionState();
207             m_objTableModel = getTableSessionStateManager().recreateTableModel(objState);
208         }
209
210         // if the session state does not help, get the model from the binding
211
if (m_objTableModel == null)
212             m_objTableModel = getCachedTableModelValue();
213
214         // if the model from the binding is null, build a model from source and columns
215
if (m_objTableModel == null)
216             m_objTableModel = generateTableModel(null);
217
218         if (m_objTableModel == null)
219             throw new ApplicationRuntimeException(TableMessages.missingTableModel(this));
220
221         return m_objTableModel;
222     }
223
224     /**
225      * Generate a table model using the 'source' and 'columns' parameters.
226      *
227      * @return the newly generated table model
228      */

229     protected ITableModel generateTableModel(SimpleTableState objState)
230     {
231         // create a new table state if none is passed
232
if (objState == null)
233         {
234             objState = new SimpleTableState();
235             objState.getSortingState().setSortColumn(getInitialSortColumn(), getInitialSortOrder());
236             objState.getPagingState().setCurrentPage(getInitialPage());
237         }
238
239         // update the page size if set in the parameter
240
if (isParameterBound("pageSize"))
241             objState.getPagingState().setPageSize(getPageSize());
242
243         // get the column model. if not possible, return null.
244
ITableColumnModel objColumnModel = getTableColumnModel();
245         if (objColumnModel == null)
246             return null;
247
248         Object JavaDoc objSourceValue = getSource();
249         if (objSourceValue == null)
250             return null;
251
252         // if the source parameter is of type {@link IBasicTableModel},
253
// create and return an appropriate wrapper
254
if (objSourceValue instanceof IBasicTableModel)
255             return new BasicTableModelWrap((IBasicTableModel) objSourceValue, objColumnModel,
256                     objState);
257
258         // otherwise, the source parameter must contain the data to be displayed
259
ITableDataModel objDataModel = null;
260         if (objSourceValue instanceof Object JavaDoc[])
261             objDataModel = new SimpleListTableDataModel((Object JavaDoc[]) objSourceValue);
262         else if (objSourceValue instanceof List JavaDoc)
263             objDataModel = new SimpleListTableDataModel((List JavaDoc) objSourceValue);
264         else if (objSourceValue instanceof Collection JavaDoc)
265             objDataModel = new SimpleListTableDataModel((Collection JavaDoc) objSourceValue);
266         else if (objSourceValue instanceof Iterator JavaDoc)
267             objDataModel = new SimpleListTableDataModel((Iterator JavaDoc) objSourceValue);
268
269         if (objDataModel == null)
270             throw new ApplicationRuntimeException(TableMessages.invalidTableSource(
271                     this,
272                     objSourceValue));
273
274         return new SimpleTableModel(objDataModel, objColumnModel, objState);
275     }
276
277     /**
278      * Returns the table column model as specified by the 'columns' binding. If the value of the
279      * 'columns' binding is of a type different than ITableColumnModel, this method makes the
280      * appropriate conversion.
281      *
282      * @return The table column model as specified by the 'columns' binding
283      */

284     protected ITableColumnModel getTableColumnModel()
285     {
286         Object JavaDoc objColumns = getColumns();
287
288         if (objColumns == null)
289             return null;
290
291         if (objColumns instanceof ITableColumnModel)
292         {
293             return (ITableColumnModel) objColumns;
294         }
295
296         if (objColumns instanceof Iterator JavaDoc)
297         {
298             // convert to List
299
Iterator JavaDoc objColumnsIterator = (Iterator JavaDoc) objColumns;
300             List JavaDoc arrColumnsList = new ArrayList JavaDoc();
301             addAll(arrColumnsList, objColumnsIterator);
302             objColumns = arrColumnsList;
303         }
304
305         if (objColumns instanceof List JavaDoc)
306         {
307             // validate that the list contains only ITableColumn instances
308
List JavaDoc arrColumnsList = (List JavaDoc) objColumns;
309             int nColumnsNumber = arrColumnsList.size();
310             for (int i = 0; i < nColumnsNumber; i++)
311             {
312                 if (!(arrColumnsList.get(i) instanceof ITableColumn))
313                     throw new ApplicationRuntimeException(TableMessages.columnsOnlyPlease(this));
314             }
315             //objColumns = arrColumnsList.toArray(new ITableColumn[nColumnsNumber]);
316
return new SimpleTableColumnModel(arrColumnsList);
317         }
318
319         if (objColumns instanceof ITableColumn[])
320         {
321             return new SimpleTableColumnModel((ITableColumn[]) objColumns);
322         }
323
324         if (objColumns instanceof String JavaDoc)
325         {
326             String JavaDoc strColumns = (String JavaDoc) objColumns;
327             if (getBinding("columns").isInvariant())
328             {
329                 // if the binding is invariant, create the columns only once
330
if (m_objColumnModel == null)
331                     m_objColumnModel = generateTableColumnModel(strColumns);
332                 return m_objColumnModel;
333             }
334
335             // if the binding is not invariant, create them every time
336
return generateTableColumnModel(strColumns);
337         }
338
339         throw new ApplicationRuntimeException(TableMessages.invalidTableColumns(this, objColumns));
340     }
341
342     private void addAll(List JavaDoc arrColumnsList, Iterator JavaDoc objColumnsIterator)
343     {
344         while (objColumnsIterator.hasNext())
345             arrColumnsList.add(objColumnsIterator.next());
346     }
347
348     /**
349      * Generate a table column model out of the description string provided. Entries in the
350      * description string are separated by commas. Each column entry is of the format name,
351      * name:expression, or name:displayName:expression. An entry prefixed with ! represents a
352      * non-sortable column. If the whole description string is prefixed with *, it represents
353      * columns to be included in a Form.
354      *
355      * @param strDesc
356      * the description of the column model to be generated
357      * @return a table column model based on the provided description
358      */

359     protected ITableColumnModel generateTableColumnModel(String JavaDoc strDesc)
360     {
361         IComponent objColumnSettingsContainer = getColumnSettingsContainer();
362         IAdvancedTableColumnSource objColumnSource = getColumnSource();
363         
364         return getModelSource().generateTableColumnModel(objColumnSource, strDesc, this, objColumnSettingsContainer);
365     }
366
367     /**
368      * The default session state manager to be used in case no such manager is provided by the
369      * corresponding parameter.
370      *
371      * @return the default session state manager
372      */

373     public ITableSessionStateManager getDefaultTableSessionStateManager()
374     {
375         if (m_objDefaultSessionStateManager == null)
376             m_objDefaultSessionStateManager = new TableViewSessionStateManager(this);
377         return m_objDefaultSessionStateManager;
378     }
379
380     /**
381      * Invoked when there is a modification of the table state and it needs to be saved
382      *
383      * @see org.apache.tapestry.contrib.table.model.ITableModelSource#fireObservedStateChange()
384      */

385     public void fireObservedStateChange()
386     {
387         saveSessionState();
388     }
389
390     /**
391      * Ensures that the table state is saved before the render phase begins in case there are
392      * modifications for which {@link #fireObservedStateChange()}has not been invoked.
393      *
394      * @see org.apache.tapestry.event.PageBeginRenderListener#pageBeginRender(org.apache.tapestry.event.PageEvent)
395      */

396     public void pageBeginRender(PageEvent event)
397     {
398         // 'suspenders': save the table model if it has been already loaded.
399
// this means that if a change has been made explicitly in a listener,
400
// it will be saved. this is the last place before committing the changes
401
// where a save can occur
402
if (m_objTableModel != null)
403             saveSessionState();
404     }
405
406     /**
407      * Saves the table state using the SessionStateManager to determine what to save and the
408      * SessionStoreManager to determine where to save it.
409      */

410     protected void saveSessionState()
411     {
412         ITableModel objModel = getTableModel();
413         Serializable JavaDoc objState = getTableSessionStateManager().getSessionState(objModel);
414         storeSessionState(objState);
415     }
416
417     /**
418      * Loads the table state using the SessionStoreManager.
419      *
420      * @return the stored table state
421      */

422     protected Serializable JavaDoc loadSessionState()
423     {
424         ITableSessionStoreManager objManager = getTableSessionStoreManager();
425         if (objManager != null)
426             return objManager.loadState(getPage().getRequestCycle());
427         String JavaDoc strPersist = getPersist();
428         if (strPersist.equals("client") || strPersist.equals("client:page"))
429             return getClientState();
430         else if (strPersist.equals("client:app"))
431             return getClientAppState();
432         else
433             return getSessionState();
434     }
435
436     /**
437      * Stores the table state using the SessionStoreManager.
438      *
439      * @param objState
440      * the table state to store
441      */

442     protected void storeSessionState(Serializable JavaDoc objState)
443     {
444         ITableSessionStoreManager objManager = getTableSessionStoreManager();
445         if (objManager != null)
446             objManager.saveState(getPage().getRequestCycle(), objState);
447         else {
448             String JavaDoc strPersist = getPersist();
449             if (strPersist.equals("client") || strPersist.equals("client:page"))
450                 setClientState(objState);
451             else if (strPersist.equals("client:app"))
452                 setClientAppState(objState);
453             else
454                 setSessionState(objState);
455         }
456     }
457
458     /**
459      * Make sure that the values stored in the model are useable and correct. The changes made here
460      * are not saved.
461      */

462     protected void validateValues()
463     {
464         ITableModel objModel = getTableModel();
465
466         // make sure current page is within the allowed range
467
ITablePagingState objPagingState = objModel.getPagingState();
468         int nCurrentPage = objPagingState.getCurrentPage();
469         int nPageCount = objModel.getPageCount();
470         if (nCurrentPage >= nPageCount)
471         {
472             // the current page is greater than the page count. adjust.
473
nCurrentPage = nPageCount - 1;
474             objPagingState.setCurrentPage(nCurrentPage);
475         }
476         if (nCurrentPage < 0)
477         {
478             // the current page is before the first page. adjust.
479
nCurrentPage = 0;
480             objPagingState.setCurrentPage(nCurrentPage);
481         }
482     }
483
484     /**
485      * Stores a pointer to this component in the Request Cycle while rendering so that wrapped
486      * components have access to it.
487      *
488      * @see org.apache.tapestry.BaseComponent#renderComponent(IMarkupWriter, IRequestCycle)
489      */

490     protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
491     {
492         Object JavaDoc objOldValue = cycle.getAttribute(ITableModelSource.TABLE_MODEL_SOURCE_ATTRIBUTE);
493         cycle.setAttribute(ITableModelSource.TABLE_MODEL_SOURCE_ATTRIBUTE, this);
494
495         initialize();
496         validateValues();
497         super.renderComponent(writer, cycle);
498
499         cycle.setAttribute(ITableModelSource.TABLE_MODEL_SOURCE_ATTRIBUTE, objOldValue);
500     }
501
502 }
Popular Tags