Clover coverage report - Code Coverage for tapestry-contrib release 4.0.1
Coverage timestamp: Fri Mar 31 2006 09:15:40 EST
file stats: LOC: 503   Methods: 18
NCLOC: 259   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
TableView.java 0% 0% 0% 0%
coverage
 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;
 18    import java.util.ArrayList;
 19    import java.util.Collection;
 20    import java.util.Iterator;
 21    import java.util.List;
 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 getSource();
 120   
 121    public abstract Object getColumns();
 122   
 123    public abstract int getInitialPage();
 124   
 125    public abstract String 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 getPersist();
 138   
 139    // enhanced property methods
 140    public abstract Serializable getSessionState();
 141   
 142    public abstract void setSessionState(Serializable sessionState);
 143   
 144    public abstract Serializable getClientState();
 145   
 146    public abstract void setClientState(Serializable sessionState);
 147   
 148    public abstract Serializable getClientAppState();
 149   
 150    public abstract void setClientAppState(Serializable sessionState);
 151   
 152    /**
 153    * The component constructor. Invokes the component member initializations.
 154    */
 155  0 public TableView()
 156    {
 157  0 initialize();
 158    }
 159   
 160    /**
 161    * Invokes the component member initializations.
 162    *
 163    * @see org.apache.tapestry.event.PageDetachListener#pageDetached(PageEvent)
 164    */
 165  0 public void pageDetached(PageEvent objEvent)
 166    {
 167  0 initialize();
 168    }
 169   
 170    /**
 171    * Initialize the component member variables.
 172    */
 173  0 private void initialize()
 174    {
 175  0 m_objTableModel = null;
 176  0 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  0 public void reset()
 184    {
 185  0 initialize();
 186  0 storeSessionState(null);
 187    }
 188   
 189  0 public ITableModel getCachedTableModelValue()
 190    {
 191  0 if (m_objCachedTableModelValue == null)
 192  0 m_objCachedTableModelValue = getTableModelValue();
 193  0 return m_objCachedTableModelValue;
 194    }
 195   
 196    /**
 197    * Returns the tableModel.
 198    *
 199    * @return ITableModel the table model used by the table components
 200    */
 201  0 public ITableModel getTableModel()
 202    {
 203    // if null, first try to recreate the model from the session state
 204  0 if (m_objTableModel == null)
 205    {
 206  0 Serializable objState = loadSessionState();
 207  0 ITableSessionStateManager objStateManager = getTableSessionStateManager();
 208  0 m_objTableModel = objStateManager.recreateTableModel(objState);
 209    }
 210   
 211    // if the session state does not help, get the model from the binding
 212  0 if (m_objTableModel == null)
 213  0 m_objTableModel = getCachedTableModelValue();
 214   
 215    // if the model from the binding is null, build a model from source and columns
 216  0 if (m_objTableModel == null)
 217  0 m_objTableModel = generateTableModel(null);
 218   
 219  0 if (m_objTableModel == null)
 220  0 throw new ApplicationRuntimeException(TableMessages.missingTableModel(this));
 221   
 222  0 return m_objTableModel;
 223    }
 224   
 225    /**
 226    * Generate a table model using the 'source' and 'columns' parameters.
 227    *
 228    * @return the newly generated table model
 229    */
 230  0 protected ITableModel generateTableModel(SimpleTableState objState)
 231    {
 232    // create a new table state if none is passed
 233  0 if (objState == null)
 234    {
 235  0 objState = new SimpleTableState();
 236  0 objState.getSortingState().setSortColumn(getInitialSortColumn(), getInitialSortOrder());
 237  0 objState.getPagingState().setCurrentPage(getInitialPage());
 238    }
 239   
 240    // update the page size if set in the parameter
 241  0 if (isParameterBound("pageSize"))
 242  0 objState.getPagingState().setPageSize(getPageSize());
 243   
 244    // get the column model. if not possible, return null.
 245  0 ITableColumnModel objColumnModel = getTableColumnModel();
 246  0 if (objColumnModel == null)
 247  0 return null;
 248   
 249  0 Object objSourceValue = getSource();
 250  0 if (objSourceValue == null)
 251  0 return null;
 252   
 253    // if the source parameter is of type {@link IBasicTableModel},
 254    // create and return an appropriate wrapper
 255  0 if (objSourceValue instanceof IBasicTableModel)
 256  0 return new BasicTableModelWrap((IBasicTableModel) objSourceValue, objColumnModel,
 257    objState);
 258   
 259    // otherwise, the source parameter must contain the data to be displayed
 260  0 ITableDataModel objDataModel = null;
 261  0 if (objSourceValue instanceof Object[])
 262  0 objDataModel = new SimpleListTableDataModel((Object[]) objSourceValue);
 263  0 else if (objSourceValue instanceof List)
 264  0 objDataModel = new SimpleListTableDataModel((List) objSourceValue);
 265  0 else if (objSourceValue instanceof Collection)
 266  0 objDataModel = new SimpleListTableDataModel((Collection) objSourceValue);
 267  0 else if (objSourceValue instanceof Iterator)
 268  0 objDataModel = new SimpleListTableDataModel((Iterator) objSourceValue);
 269   
 270  0 if (objDataModel == null)
 271  0 throw new ApplicationRuntimeException(TableMessages.invalidTableSource(
 272    this,
 273    objSourceValue));
 274   
 275  0 return new SimpleTableModel(objDataModel, objColumnModel, objState);
 276    }
 277   
 278    /**
 279    * Returns the table column model as specified by the 'columns' binding. If the value of the
 280    * 'columns' binding is of a type different than ITableColumnModel, this method makes the
 281    * appropriate conversion.
 282    *
 283    * @return The table column model as specified by the 'columns' binding
 284    */
 285  0 protected ITableColumnModel getTableColumnModel()
 286    {
 287  0 Object objColumns = getColumns();
 288   
 289  0 if (objColumns == null)
 290  0 return null;
 291   
 292  0 if (objColumns instanceof ITableColumnModel)
 293    {
 294  0 return (ITableColumnModel) objColumns;
 295    }
 296   
 297  0 if (objColumns instanceof Iterator)
 298    {
 299    // convert to List
 300  0 Iterator objColumnsIterator = (Iterator) objColumns;
 301  0 List arrColumnsList = new ArrayList();
 302  0 addAll(arrColumnsList, objColumnsIterator);
 303  0 objColumns = arrColumnsList;
 304    }
 305   
 306  0 if (objColumns instanceof List)
 307    {
 308    // validate that the list contains only ITableColumn instances
 309  0 List arrColumnsList = (List) objColumns;
 310  0 int nColumnsNumber = arrColumnsList.size();
 311  0 for (int i = 0; i < nColumnsNumber; i++)
 312    {
 313  0 if (!(arrColumnsList.get(i) instanceof ITableColumn))
 314  0 throw new ApplicationRuntimeException(TableMessages.columnsOnlyPlease(this));
 315    }
 316    //objColumns = arrColumnsList.toArray(new ITableColumn[nColumnsNumber]);
 317  0 return new SimpleTableColumnModel(arrColumnsList);
 318    }
 319   
 320  0 if (objColumns instanceof ITableColumn[])
 321    {
 322  0 return new SimpleTableColumnModel((ITableColumn[]) objColumns);
 323    }
 324   
 325  0 if (objColumns instanceof String)
 326    {
 327  0 String strColumns = (String) objColumns;
 328  0 if (getBinding("columns").isInvariant())
 329    {
 330    // if the binding is invariant, create the columns only once
 331  0 if (m_objColumnModel == null)
 332  0 m_objColumnModel = generateTableColumnModel(strColumns);
 333  0 return m_objColumnModel;
 334    }
 335   
 336    // if the binding is not invariant, create them every time
 337  0 return generateTableColumnModel(strColumns);
 338    }
 339   
 340  0 throw new ApplicationRuntimeException(TableMessages.invalidTableColumns(this, objColumns));
 341    }
 342   
 343  0 private void addAll(List arrColumnsList, Iterator objColumnsIterator)
 344    {
 345  0 while (objColumnsIterator.hasNext())
 346  0 arrColumnsList.add(objColumnsIterator.next());
 347    }
 348   
 349    /**
 350    * Generate a table column model out of the description string provided. Entries in the
 351    * description string are separated by commas. Each column entry is of the format name,
 352    * name:expression, or name:displayName:expression. An entry prefixed with ! represents a
 353    * non-sortable column. If the whole description string is prefixed with *, it represents
 354    * columns to be included in a Form.
 355    *
 356    * @param strDesc
 357    * the description of the column model to be generated
 358    * @return a table column model based on the provided description
 359    */
 360  0 protected ITableColumnModel generateTableColumnModel(String strDesc)
 361    {
 362  0 IComponent objColumnSettingsContainer = getColumnSettingsContainer();
 363  0 IAdvancedTableColumnSource objColumnSource = getColumnSource();
 364   
 365  0 return getModelSource().generateTableColumnModel(objColumnSource, strDesc, this, objColumnSettingsContainer);
 366    }
 367   
 368    /**
 369    * The default session state manager to be used in case no such manager is provided by the
 370    * corresponding parameter.
 371    *
 372    * @return the default session state manager
 373    */
 374  0 public ITableSessionStateManager getDefaultTableSessionStateManager()
 375    {
 376  0 if (m_objDefaultSessionStateManager == null)
 377  0 m_objDefaultSessionStateManager = new TableViewSessionStateManager(this);
 378  0 return m_objDefaultSessionStateManager;
 379    }
 380   
 381    /**
 382    * Invoked when there is a modification of the table state and it needs to be saved
 383    *
 384    * @see org.apache.tapestry.contrib.table.model.ITableModelSource#fireObservedStateChange()
 385    */
 386  0 public void fireObservedStateChange()
 387    {
 388  0 saveSessionState();
 389    }
 390   
 391    /**
 392    * Ensures that the table state is saved before the render phase begins in case there are
 393    * modifications for which {@link #fireObservedStateChange()}has not been invoked.
 394    *
 395    * @see org.apache.tapestry.event.PageBeginRenderListener#pageBeginRender(org.apache.tapestry.event.PageEvent)
 396    */
 397  0 public void pageBeginRender(PageEvent event)
 398    {
 399    // 'suspenders': save the table model if it has been already loaded.
 400    // this means that if a change has been made explicitly in a listener,
 401    // it will be saved. this is the last place before committing the changes
 402    // where a save can occur
 403  0 if (m_objTableModel != null)
 404  0 saveSessionState();
 405    }
 406   
 407    /**
 408    * Saves the table state using the SessionStateManager to determine what to save and the
 409    * SessionStoreManager to determine where to save it.
 410    */
 411  0 protected void saveSessionState()
 412    {
 413  0 ITableModel objModel = getTableModel();
 414  0 Serializable objState = getTableSessionStateManager().getSessionState(objModel);
 415  0 storeSessionState(objState);
 416    }
 417   
 418    /**
 419    * Loads the table state using the SessionStoreManager.
 420    *
 421    * @return the stored table state
 422    */
 423  0 protected Serializable loadSessionState()
 424    {
 425  0 ITableSessionStoreManager objManager = getTableSessionStoreManager();
 426  0 if (objManager != null)
 427  0 return objManager.loadState(getPage().getRequestCycle());
 428  0 String strPersist = getPersist();
 429  0 if (strPersist.equals("client") || strPersist.equals("client:page"))
 430  0 return getClientState();
 431  0 else if (strPersist.equals("client:app"))
 432  0 return getClientAppState();
 433    else
 434  0 return getSessionState();
 435    }
 436   
 437    /**
 438    * Stores the table state using the SessionStoreManager.
 439    *
 440    * @param objState
 441    * the table state to store
 442    */
 443  0 protected void storeSessionState(Serializable objState)
 444    {
 445  0 ITableSessionStoreManager objManager = getTableSessionStoreManager();
 446  0 if (objManager != null)
 447  0 objManager.saveState(getPage().getRequestCycle(), objState);
 448    else {
 449  0 String strPersist = getPersist();
 450  0 if (strPersist.equals("client") || strPersist.equals("client:page"))
 451  0 setClientState(objState);
 452  0 else if (strPersist.equals("client:app"))
 453  0 setClientAppState(objState);
 454    else
 455  0 setSessionState(objState);
 456    }
 457    }
 458   
 459    /**
 460    * Make sure that the values stored in the model are useable and correct. The changes made here
 461    * are not saved.
 462    */
 463  0 protected void validateValues()
 464    {
 465  0 ITableModel objModel = getTableModel();
 466   
 467    // make sure current page is within the allowed range
 468  0 ITablePagingState objPagingState = objModel.getPagingState();
 469  0 int nCurrentPage = objPagingState.getCurrentPage();
 470  0 int nPageCount = objModel.getPageCount();
 471  0 if (nCurrentPage >= nPageCount)
 472    {
 473    // the current page is greater than the page count. adjust.
 474  0 nCurrentPage = nPageCount - 1;
 475  0 objPagingState.setCurrentPage(nCurrentPage);
 476    }
 477  0 if (nCurrentPage < 0)
 478    {
 479    // the current page is before the first page. adjust.
 480  0 nCurrentPage = 0;
 481  0 objPagingState.setCurrentPage(nCurrentPage);
 482    }
 483    }
 484   
 485    /**
 486    * Stores a pointer to this component in the Request Cycle while rendering so that wrapped
 487    * components have access to it.
 488    *
 489    * @see org.apache.tapestry.BaseComponent#renderComponent(IMarkupWriter, IRequestCycle)
 490    */
 491  0 protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
 492    {
 493  0 Object objOldValue = cycle.getAttribute(ITableModelSource.TABLE_MODEL_SOURCE_ATTRIBUTE);
 494  0 cycle.setAttribute(ITableModelSource.TABLE_MODEL_SOURCE_ATTRIBUTE, this);
 495   
 496  0 initialize();
 497  0 validateValues();
 498  0 super.renderComponent(writer, cycle);
 499   
 500  0 cycle.setAttribute(ITableModelSource.TABLE_MODEL_SOURCE_ATTRIBUTE, objOldValue);
 501    }
 502   
 503    }