Clover coverage report - Code Coverage for tapestry-contrib release 4.0-alpha-3
Coverage timestamp: Mon May 16 2005 09:12:41 EDT
file stats: LOC: 475   Methods: 18
NCLOC: 237   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 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.IBasicTableModel;
 29   
 import org.apache.tapestry.contrib.table.model.ITableColumn;
 30   
 import org.apache.tapestry.contrib.table.model.ITableColumnModel;
 31   
 import org.apache.tapestry.contrib.table.model.ITableDataModel;
 32   
 import org.apache.tapestry.contrib.table.model.ITableModel;
 33   
 import org.apache.tapestry.contrib.table.model.ITableModelSource;
 34   
 import org.apache.tapestry.contrib.table.model.ITablePagingState;
 35   
 import org.apache.tapestry.contrib.table.model.ITableSessionStateManager;
 36   
 import org.apache.tapestry.contrib.table.model.ITableSessionStoreManager;
 37   
 import org.apache.tapestry.contrib.table.model.common.BasicTableModelWrap;
 38   
 import org.apache.tapestry.contrib.table.model.simple.SimpleListTableDataModel;
 39   
 import org.apache.tapestry.contrib.table.model.simple.SimpleTableColumnModel;
 40   
 import org.apache.tapestry.contrib.table.model.simple.SimpleTableModel;
 41   
 import org.apache.tapestry.contrib.table.model.simple.SimpleTableState;
 42   
 import org.apache.tapestry.event.PageBeginRenderListener;
 43   
 import org.apache.tapestry.event.PageDetachListener;
 44   
 import org.apache.tapestry.event.PageEvent;
 45   
 
 46   
 /**
 47   
  * A low level Table component that wraps all other low level Table components. This component
 48   
  * carries the {@link org.apache.tapestry.contrib.table.model.ITableModel}that is used by the other
 49   
  * Table components. Please see the documentation of
 50   
  * {@link org.apache.tapestry.contrib.table.model.ITableModel}if you need to know more about how a
 51   
  * table is represented.
 52   
  * <p>
 53   
  * This component also handles the saving of the state of the model using an
 54   
  * {@link org.apache.tapestry.contrib.table.model.ITableSessionStateManager}to determine what part
 55   
  * of the model is to be saved and an
 56   
  * {@link  org.apache.tapestry.contrib.table.model.ITableSessionStoreManager}to determine how to
 57   
  * save it.
 58   
  * <p>
 59   
  * Upon the beginning of a new request cycle when the table model is first needed, the model is
 60   
  * obtained using the following process:
 61   
  * <ul>
 62   
  * <li>The persistent state of the table is loaded. If the tableSessionStoreManager binding has not
 63   
  * been bound, the state is loaded from a persistent property within the component (it is null at
 64   
  * the beginning). Otherwise the supplied
 65   
  * {@link  org.apache.tapestry.contrib.table.model.ITableSessionStoreManager}is used to load the
 66   
  * persistent state.
 67   
  * <li>The table model is recreated using the
 68   
  * {@link org.apache.tapestry.contrib.table.model.ITableSessionStateManager}that could be supplied
 69   
  * using the tableSessionStateManager binding (but has a default value and is therefore not
 70   
  * required).
 71   
  * <li>If the {@link org.apache.tapestry.contrib.table.model.ITableSessionStateManager}returns
 72   
  * null, then a table model is taken from the tableModel binding. Thus, if the
 73   
  * {@link org.apache.tapestry.contrib.table.model.common.NullTableSessionStateManager}is used, the
 74   
  * table model would be taken from the tableModel binding every time.
 75   
  * </ul>
 76   
  * Just before the rendering phase the persistent state of the model is saved in the session. This
 77   
  * process occurs in reverse:
 78   
  * <ul>
 79   
  * <li>The persistent state of the model is taken via the
 80   
  * {@link org.apache.tapestry.contrib.table.model.ITableSessionStateManager}.
 81   
  * <li>If the tableSessionStoreManager binding has not been bound, the persistent state is saved as
 82   
  * a persistent page property. Otherwise the supplied
 83   
  * {@link  org.apache.tapestry.contrib.table.model.ITableSessionStoreManager}is used to save the
 84   
  * persistent state. Use of the
 85   
  * {@link  org.apache.tapestry.contrib.table.model.ITableSessionStoreManager}is usually necessary
 86   
  * when tables with the same model have to be used across multiple pages, and hence the state has to
 87   
  * be saved in the Visit, rather than in a persistent component property.
 88   
  * </ul>
 89   
  * <p>
 90   
  * <p>
 91   
  * Please see the Component Reference for details on how to use this component. [ <a
 92   
  * href="../../../../../../../ComponentReference/contrib.TableView.html">Component Reference </a>]
 93   
  * 
 94   
  * @author mindbridge
 95   
  */
 96   
 public abstract class TableView extends BaseComponent implements PageDetachListener,
 97   
         PageBeginRenderListener, ITableModelSource
 98   
 {
 99   
     /** @since 4.0 */
 100   
 
 101   
     public abstract TableColumnModelSource getModelSource();
 102   
 
 103   
     // Component properties
 104   
     private ITableSessionStateManager m_objDefaultSessionStateManager = null;
 105   
 
 106   
     private ITableColumnModel m_objColumnModel = null;
 107   
 
 108   
     // Transient objects
 109   
     private ITableModel m_objTableModel;
 110   
 
 111   
     private ITableModel m_objCachedTableModelValue;
 112   
 
 113   
     // enhanced parameter methods
 114   
     public abstract ITableModel getTableModelValue();
 115   
 
 116   
     public abstract Object getSource();
 117   
 
 118   
     public abstract Object getColumns();
 119   
 
 120   
     public abstract int getInitialPage();
 121   
 
 122   
     public abstract String getInitialSortColumn();
 123   
 
 124   
     public abstract boolean getInitialSortOrder();
 125   
 
 126   
     public abstract ITableSessionStateManager getTableSessionStateManager();
 127   
 
 128   
     public abstract ITableSessionStoreManager getTableSessionStoreManager();
 129   
 
 130   
     public abstract IComponent getColumnSettingsContainer();
 131   
 
 132   
     public abstract int getPageSize();
 133   
 
 134   
     // enhanced property methods
 135   
     public abstract Serializable getSessionState();
 136   
 
 137   
     public abstract void setSessionState(Serializable sessionState);
 138   
 
 139   
     /**
 140   
      * The component constructor. Invokes the component member initializations.
 141   
      */
 142  0
     public TableView()
 143   
     {
 144  0
         initialize();
 145   
     }
 146   
 
 147   
     /**
 148   
      * Invokes the component member initializations.
 149   
      * 
 150   
      * @see org.apache.tapestry.event.PageDetachListener#pageDetached(PageEvent)
 151   
      */
 152  0
     public void pageDetached(PageEvent objEvent)
 153   
     {
 154  0
         initialize();
 155   
     }
 156   
 
 157   
     /**
 158   
      * Initialize the component member variables.
 159   
      */
 160  0
     private void initialize()
 161   
     {
 162  0
         m_objTableModel = null;
 163  0
         m_objCachedTableModelValue = null;
 164   
     }
 165   
 
 166   
     /**
 167   
      * Resets the table by removing any stored table state. This means that the current column to
 168   
      * sort on and the current page will be forgotten and all data will be reloaded.
 169   
      */
 170  0
     public void reset()
 171   
     {
 172  0
         initialize();
 173  0
         storeSessionState(null);
 174   
     }
 175   
 
 176  0
     public ITableModel getCachedTableModelValue()
 177   
     {
 178  0
         if (m_objCachedTableModelValue == null)
 179  0
             m_objCachedTableModelValue = getTableModelValue();
 180  0
         return m_objCachedTableModelValue;
 181   
     }
 182   
 
 183   
     /**
 184   
      * Returns the tableModel.
 185   
      * 
 186   
      * @return ITableModel the table model used by the table components
 187   
      */
 188  0
     public ITableModel getTableModel()
 189   
     {
 190   
         // if null, first try to recreate the model from the session state
 191  0
         if (m_objTableModel == null)
 192   
         {
 193  0
             Serializable objState = loadSessionState();
 194  0
             m_objTableModel = getTableSessionStateManager().recreateTableModel(objState);
 195   
         }
 196   
 
 197   
         // if the session state does not help, get the model from the binding
 198  0
         if (m_objTableModel == null)
 199  0
             m_objTableModel = getCachedTableModelValue();
 200   
 
 201   
         // if the model from the binding is null, build a model from source and columns
 202  0
         if (m_objTableModel == null)
 203  0
             m_objTableModel = generateTableModel(null);
 204   
 
 205  0
         if (m_objTableModel == null)
 206  0
             throw new ApplicationRuntimeException(TableMessages.missingTableModel(this));
 207   
 
 208  0
         return m_objTableModel;
 209   
     }
 210   
 
 211   
     /**
 212   
      * Generate a table model using the 'source' and 'columns' parameters.
 213   
      * 
 214   
      * @return the newly generated table model
 215   
      */
 216  0
     protected ITableModel generateTableModel(SimpleTableState objState)
 217   
     {
 218   
         // create a new table state if none is passed
 219  0
         if (objState == null)
 220   
         {
 221  0
             objState = new SimpleTableState();
 222  0
             objState.getSortingState().setSortColumn(getInitialSortColumn(), getInitialSortOrder());
 223  0
             objState.getPagingState().setCurrentPage(getInitialPage());
 224   
         }
 225   
 
 226   
         // update the page size if set in the parameter
 227  0
         if (isParameterBound("pageSize"))
 228  0
             objState.getPagingState().setPageSize(getPageSize());
 229   
 
 230   
         // get the column model. if not possible, return null.
 231  0
         ITableColumnModel objColumnModel = getTableColumnModel();
 232  0
         if (objColumnModel == null)
 233  0
             return null;
 234   
 
 235  0
         Object objSourceValue = getSource();
 236  0
         if (objSourceValue == null)
 237  0
             return null;
 238   
 
 239   
         // if the source parameter is of type {@link IBasicTableModel},
 240   
         // create and return an appropriate wrapper
 241  0
         if (objSourceValue instanceof IBasicTableModel)
 242  0
             return new BasicTableModelWrap((IBasicTableModel) objSourceValue, objColumnModel,
 243   
                     objState);
 244   
 
 245   
         // otherwise, the source parameter must contain the data to be displayed
 246  0
         ITableDataModel objDataModel = null;
 247  0
         if (objSourceValue instanceof Object[])
 248  0
             objDataModel = new SimpleListTableDataModel((Object[]) objSourceValue);
 249  0
         else if (objSourceValue instanceof List)
 250  0
             objDataModel = new SimpleListTableDataModel((List) objSourceValue);
 251  0
         else if (objSourceValue instanceof Collection)
 252  0
             objDataModel = new SimpleListTableDataModel((Collection) objSourceValue);
 253  0
         else if (objSourceValue instanceof Iterator)
 254  0
             objDataModel = new SimpleListTableDataModel((Iterator) objSourceValue);
 255   
 
 256  0
         if (objDataModel == null)
 257  0
             throw new ApplicationRuntimeException(TableMessages.invalidTableSource(
 258   
                     this,
 259   
                     objSourceValue));
 260   
 
 261  0
         return new SimpleTableModel(objDataModel, objColumnModel, objState);
 262   
     }
 263   
 
 264   
     /**
 265   
      * Returns the table column model as specified by the 'columns' binding. If the value of the
 266   
      * 'columns' binding is of a type different than ITableColumnModel, this method makes the
 267   
      * appropriate conversion.
 268   
      * 
 269   
      * @return The table column model as specified by the 'columns' binding
 270   
      */
 271  0
     protected ITableColumnModel getTableColumnModel()
 272   
     {
 273  0
         Object objColumns = getColumns();
 274   
 
 275  0
         if (objColumns == null)
 276  0
             return null;
 277   
 
 278  0
         if (objColumns instanceof ITableColumnModel)
 279   
         {
 280  0
             return (ITableColumnModel) objColumns;
 281   
         }
 282   
 
 283  0
         if (objColumns instanceof Iterator)
 284   
         {
 285   
             // convert to List
 286  0
             Iterator objColumnsIterator = (Iterator) objColumns;
 287  0
             List arrColumnsList = new ArrayList();
 288  0
             addAll(arrColumnsList, objColumnsIterator);
 289  0
             objColumns = arrColumnsList;
 290   
         }
 291   
 
 292  0
         if (objColumns instanceof List)
 293   
         {
 294   
             // validate that the list contains only ITableColumn instances
 295  0
             List arrColumnsList = (List) objColumns;
 296  0
             int nColumnsNumber = arrColumnsList.size();
 297  0
             for (int i = 0; i < nColumnsNumber; i++)
 298   
             {
 299  0
                 if (!(arrColumnsList.get(i) instanceof ITableColumn))
 300  0
                     throw new ApplicationRuntimeException(TableMessages.columnsOnlyPlease(this));
 301   
             }
 302   
             //objColumns = arrColumnsList.toArray(new ITableColumn[nColumnsNumber]);
 303  0
             return new SimpleTableColumnModel(arrColumnsList);
 304   
         }
 305   
 
 306  0
         if (objColumns instanceof ITableColumn[])
 307   
         {
 308  0
             return new SimpleTableColumnModel((ITableColumn[]) objColumns);
 309   
         }
 310   
 
 311  0
         if (objColumns instanceof String)
 312   
         {
 313  0
             String strColumns = (String) objColumns;
 314  0
             if (getBinding("columns").isInvariant())
 315   
             {
 316   
                 // if the binding is invariant, create the columns only once
 317  0
                 if (m_objColumnModel == null)
 318  0
                     m_objColumnModel = generateTableColumnModel(strColumns);
 319  0
                 return m_objColumnModel;
 320   
             }
 321   
 
 322   
             // if the binding is not invariant, create them every time
 323  0
             return generateTableColumnModel(strColumns);
 324   
         }
 325   
 
 326  0
         throw new ApplicationRuntimeException(TableMessages.invalidTableColumns(this, objColumns));
 327   
     }
 328   
 
 329  0
     private void addAll(List arrColumnsList, Iterator objColumnsIterator)
 330   
     {
 331  0
         while (objColumnsIterator.hasNext())
 332  0
             arrColumnsList.add(objColumnsIterator.next());
 333   
     }
 334   
 
 335   
     /**
 336   
      * Generate a table column model out of the description string provided. Entries in the
 337   
      * description string are separated by commas. Each column entry is of the format name,
 338   
      * name:expression, or name:displayName:expression. An entry prefixed with ! represents a
 339   
      * non-sortable column. If the whole description string is prefixed with *, it represents
 340   
      * columns to be included in a Form.
 341   
      * 
 342   
      * @param strDesc
 343   
      *            the description of the column model to be generated
 344   
      * @return a table column model based on the provided description
 345   
      */
 346  0
     protected ITableColumnModel generateTableColumnModel(String strDesc)
 347   
     {
 348  0
         IComponent objColumnSettingsContainer = getColumnSettingsContainer();
 349   
 
 350  0
         return getModelSource().generateTableColumnModel(strDesc, this, objColumnSettingsContainer);
 351   
     }
 352   
 
 353   
     /**
 354   
      * The default session state manager to be used in case no such manager is provided by the
 355   
      * corresponding parameter.
 356   
      * 
 357   
      * @return the default session state manager
 358   
      */
 359  0
     public ITableSessionStateManager getDefaultTableSessionStateManager()
 360   
     {
 361  0
         if (m_objDefaultSessionStateManager == null)
 362  0
             m_objDefaultSessionStateManager = new TableViewSessionStateManager(this);
 363  0
         return m_objDefaultSessionStateManager;
 364   
     }
 365   
 
 366   
     /**
 367   
      * Invoked when there is a modification of the table state and it needs to be saved
 368   
      * 
 369   
      * @see org.apache.tapestry.contrib.table.model.ITableModelSource#fireObservedStateChange()
 370   
      */
 371  0
     public void fireObservedStateChange()
 372   
     {
 373  0
         saveSessionState();
 374   
     }
 375   
 
 376   
     /**
 377   
      * Ensures that the table state is saved before the render phase begins in case there are
 378   
      * modifications for which {@link #fireObservedStateChange()}has not been invoked.
 379   
      * 
 380   
      * @see org.apache.tapestry.event.PageRenderListener#pageBeginRender(org.apache.tapestry.event.PageEvent)
 381   
      */
 382  0
     public void pageBeginRender(PageEvent event)
 383   
     {
 384   
         // 'suspenders': save the table model if it has been already loaded.
 385   
         // this means that if a change has been made explicitly in a listener,
 386   
         // it will be saved. this is the last place before committing the changes
 387   
         // where a save can occur
 388  0
         if (m_objTableModel != null)
 389  0
             saveSessionState();
 390   
     }
 391   
 
 392   
     /**
 393   
      * Saves the table state using the SessionStateManager to determine what to save and the
 394   
      * SessionStoreManager to determine where to save it.
 395   
      */
 396  0
     protected void saveSessionState()
 397   
     {
 398  0
         ITableModel objModel = getTableModel();
 399  0
         Serializable objState = getTableSessionStateManager().getSessionState(objModel);
 400  0
         storeSessionState(objState);
 401   
     }
 402   
 
 403   
     /**
 404   
      * Loads the table state using the SessionStoreManager.
 405   
      * 
 406   
      * @return the stored table state
 407   
      */
 408  0
     protected Serializable loadSessionState()
 409   
     {
 410  0
         ITableSessionStoreManager objManager = getTableSessionStoreManager();
 411  0
         if (objManager != null)
 412  0
             return objManager.loadState(getPage().getRequestCycle());
 413  0
         return getSessionState();
 414   
     }
 415   
 
 416   
     /**
 417   
      * Stores the table state using the SessionStoreManager.
 418   
      * 
 419   
      * @param objState
 420   
      *            the table state to store
 421   
      */
 422  0
     protected void storeSessionState(Serializable objState)
 423   
     {
 424  0
         ITableSessionStoreManager objManager = getTableSessionStoreManager();
 425  0
         if (objManager != null)
 426  0
             objManager.saveState(getPage().getRequestCycle(), objState);
 427   
         else
 428  0
             setSessionState(objState);
 429   
     }
 430   
 
 431   
     /**
 432   
      * Make sure that the values stored in the model are useable and correct. The changes made here
 433   
      * are not saved.
 434   
      */
 435  0
     protected void validateValues()
 436   
     {
 437  0
         ITableModel objModel = getTableModel();
 438   
 
 439   
         // make sure current page is within the allowed range
 440  0
         ITablePagingState objPagingState = objModel.getPagingState();
 441  0
         int nCurrentPage = objPagingState.getCurrentPage();
 442  0
         int nPageCount = objModel.getPageCount();
 443  0
         if (nCurrentPage >= nPageCount)
 444   
         {
 445   
             // the current page is greater than the page count. adjust.
 446  0
             nCurrentPage = nPageCount - 1;
 447  0
             objPagingState.setCurrentPage(nCurrentPage);
 448   
         }
 449  0
         if (nCurrentPage < 0)
 450   
         {
 451   
             // the current page is before the first page. adjust.
 452  0
             nCurrentPage = 0;
 453  0
             objPagingState.setCurrentPage(nCurrentPage);
 454   
         }
 455   
     }
 456   
 
 457   
     /**
 458   
      * Stores a pointer to this component in the Request Cycle while rendering so that wrapped
 459   
      * components have access to it.
 460   
      * 
 461   
      * @see org.apache.tapestry.BaseComponent#renderComponent(IMarkupWriter, IRequestCycle)
 462   
      */
 463  0
     protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
 464   
     {
 465  0
         Object objOldValue = cycle.getAttribute(ITableModelSource.TABLE_MODEL_SOURCE_ATTRIBUTE);
 466  0
         cycle.setAttribute(ITableModelSource.TABLE_MODEL_SOURCE_ATTRIBUTE, this);
 467   
 
 468  0
         initialize();
 469  0
         validateValues();
 470  0
         super.renderComponent(writer, cycle);
 471   
 
 472  0
         cycle.setAttribute(ITableModelSource.TABLE_MODEL_SOURCE_ATTRIBUTE, objOldValue);
 473   
     }
 474   
 
 475   
 }