Coverage Report - org.trails.component.ObjectTable
 
Classes in this File Line Coverage Branch Coverage Complexity
ObjectTable
43% 
46% 
0
 
 1  
 /*
 2  
  * Copyright 2004 Chris Nelson
 3  
  *
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 7  
  * Unless required by applicable law or agreed to in writing,
 8  
  * software distributed under the License is distributed on an "AS IS" BASIS,
 9  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 10  
  * See the License for the specific language governing permissions and limitations under the License.
 11  
  */
 12  
 package org.trails.component;
 13  
 
 14  
 import org.apache.commons.logging.Log;
 15  
 import org.apache.commons.logging.LogFactory;
 16  
 import org.apache.hivemind.ApplicationRuntimeException;
 17  
 import org.apache.hivemind.impl.MessageFormatter;
 18  
 import org.apache.hivemind.service.ClassFabUtils;
 19  
 import org.apache.tapestry.IAsset;
 20  
 import org.apache.tapestry.IComponent;
 21  
 import org.apache.tapestry.IRequestCycle;
 22  
 import org.apache.tapestry.annotations.ComponentClass;
 23  
 import org.apache.tapestry.annotations.InjectObject;
 24  
 import org.apache.tapestry.annotations.Parameter;
 25  
 import org.apache.tapestry.annotations.Persist;
 26  
 import org.apache.tapestry.components.Block;
 27  
 import org.apache.tapestry.contrib.table.components.TableMessages;
 28  
 import org.apache.tapestry.contrib.table.components.TableView;
 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.common.AbstractTableColumn;
 32  
 import org.apache.tapestry.contrib.table.model.common.BlockTableRendererSource;
 33  
 import org.apache.tapestry.contrib.table.model.simple.SimpleTableColumnModel;
 34  
 import org.apache.tapestry.event.PageBeginRenderListener;
 35  
 import org.apache.tapestry.event.PageEvent;
 36  
 import org.apache.tapestry.services.ExpressionEvaluator;
 37  
 import org.trails.descriptor.IPropertyDescriptor;
 38  
 import org.trails.persistence.PersistenceService;
 39  
 
 40  
 import java.util.ArrayList;
 41  
 import java.util.Iterator;
 42  
 import java.util.List;
 43  
 
 44  
 /**
 45  
  * Produces a table for the list of instances
 46  
  */
 47  
 //@GlobalComponent
 48  
 @ComponentClass(allowBody = true, allowInformalParameters = true)
 49  36
 public abstract class ObjectTable extends ClassDescriptorComponent implements PageBeginRenderListener
 50  
 {
 51  4
         private static final Log LOG = LogFactory.getLog(ObjectTable.class);
 52  
 
 53  
         public static final String LINK_COLUMN = "link" + AbstractTableColumn.VALUE_RENDERER_BLOCK_SUFFIX;
 54  
 
 55  16
         private ITableColumnModel m_objColumnModel = null;
 56  
 
 57  
         @Parameter(defaultValue = "ognl:@java.lang.System@getProperty('org.apache.tapestry.disable-caching')")
 58  
         public abstract boolean isCacheDisabled();
 59  
 
 60  
         protected List<ITableColumn> columns;
 61  
 
 62  
         @Parameter(required = false, defaultValue = "false", cache = true)
 63  
         public abstract boolean isShowCollections();
 64  
 
 65  
         public abstract void setShowCollections(boolean ShowCollections);
 66  
 
 67  
         @InjectObject("service:trails.core.PersistenceService")
 68  
         public abstract PersistenceService getPersistenceService();
 69  
 
 70  
         /**
 71  
          * The data to be displayed by the component.
 72  
          *
 73  
          * @return
 74  
          */
 75  
         @Parameter
 76  
         public abstract List getInstances();
 77  
 
 78  
         public abstract void setInstances(List instances);
 79  
 
 80  
         /**
 81  
          * If provided, the parameter is updated with the current row being rendered.
 82  
          */
 83  
         @Parameter(cache = false, defaultValue = "objectParameter")
 84  
         public abstract Object getObject();
 85  
 
 86  
         /**
 87  
          * Returns the currently rendered table row. It's used when there is no binding for the "object" parameter. This method
 88  
          * is for internal use only.
 89  
          */
 90  
         public abstract Object getObjectParameter();
 91  
         public abstract void setObjectParameter(Object object);
 92  
 
 93  
         /**
 94  
          * The object representing the current column being rendered.
 95  
          */
 96  
         @Parameter(cache = false)
 97  
         public abstract ITableColumn getColumn();
 98  
 
 99  
         /**
 100  
          * The CSS class of the table rows.
 101  
          */
 102  
         @Parameter(cache = false)
 103  
         public abstract String getRowsClass();
 104  
 
 105  
         /**
 106  
          * The CSS class of the table columns.
 107  
          */
 108  
         @Parameter(cache = false)
 109  
         public abstract String getColumnsClass();
 110  
 
 111  
         /**
 112  
          * The number of records displayed per page.
 113  
          */
 114  
         @Parameter(cache = false, defaultValue = "10")
 115  
         public abstract int getPageSize();
 116  
 
 117  
         /**
 118  
          * If provided, the parameter is updated with the index of the loop on each iteration.
 119  
          */
 120  
         @Parameter
 121  
         public abstract int getIndex();
 122  
 
 123  
         /**
 124  
          * The id of the column to initially sort the table by.
 125  
          */
 126  
         @Parameter
 127  
         public abstract String getInitialSortColumn();
 128  
 
 129  
         /**
 130  
          * The order of the initial sorting. Set this parameter to 'false' to sort in an ascending order and to 'true' to sort
 131  
          * in a descending one.
 132  
          */
 133  
         @Parameter(defaultValue = "false")
 134  
         public abstract boolean getInitialSortOrder();
 135  
 
 136  
         /**
 137  
          * Defines how the table state (paging and sorting) will be persisted if no tableSessionStoreManager is defined. The
 138  
          * possible values are 'session' (the default), 'client', 'client:page', and 'client:app'.
 139  
          */
 140  
         @Parameter(defaultValue = "literal:session")
 141  
         public abstract String getPersist();
 142  
 
 143  
         /**
 144  
          * The image to use to describe a column sorted in a descending order.
 145  
          */
 146  
         @Parameter
 147  
         public abstract IAsset getArrowDownAsset();
 148  
 
 149  
         /**
 150  
          * The image to use to describe a column sorted in an ascending order.
 151  
          */
 152  
         @Parameter
 153  
         public abstract IAsset getArrowUpAsset();
 154  
 
 155  
         /**
 156  
          * @return The table columns to be displayed.
 157  
          */
 158  
         public List<ITableColumn> getColumns()
 159  
         {
 160  20
                 return !isCacheDisabled() && getColumnsCache() != null ? getColumnsCache() : columns;
 161  
         }
 162  
 
 163  
         @Persist
 164  
         public abstract List<ITableColumn> getColumnsCache();
 165  
 
 166  
         public abstract void setColumnsCache(List<ITableColumn> columns);
 167  
 
 168  
         /**
 169  
          * This parameter provides a new set of columns to be displayed after the ones provided by the IClassDescriptor or
 170  
          * EditProperties parameters. The parameter works like the [<a href="http://tapestry.apache.org/tapestry4.1/tapestry-contrib/componentreference/table.html">contrib
 171  
          * table</a>] 'columns' parameter. The parameter must be an array, a list, or an Iterator of ITableColumn objects, an
 172  
          * ITableColumnModel, or a String describing the columns (see documentation).
 173  
          */
 174  
         @Parameter
 175  
         public abstract Object getExtraColumns();
 176  
 
 177  
         public abstract void setExtraColumns(Object o);
 178  
 
 179  
         @InjectObject("service:tapestry.ognl.ExpressionEvaluator")
 180  
         public abstract ExpressionEvaluator getEvaluator();
 181  
 
 182  
         @Override
 183  
         protected void prepareForRender(IRequestCycle cycle)
 184  
         {
 185  
                 /**
 186  
                  * If getColumnsCache() == null means that pageBeginRender wasn't fired because the component is inside a Block
 187  
                  * in another page.
 188  
                  */
 189  24
                 if (getColumnsCache() == null || isCacheDisabled())
 190  
                 {
 191  24
                         columns = createColumns();
 192  
                 }
 193  24
                 super.prepareForRender(cycle);
 194  24
         }
 195  
 
 196  
         public void pageBeginRender(PageEvent event)
 197  
         {
 198  0
                 if (!event.getRequestCycle().isRewinding())
 199  
                 {
 200  0
                         setColumnsCache(createColumns());
 201  
                 }
 202  0
         }
 203  
 
 204  
         /**
 205  
          * It creates a {@link ITableColumn} list out of the IClassDescriptor metadata. It's meant to be used as a {@link
 206  
          * ITableColumnModel} by the inner table.
 207  
          *
 208  
          * @return A {@link ITableColumn} list
 209  
          */
 210  
         private List<ITableColumn> createColumns()
 211  
         {
 212  24
                 List<ITableColumn> columns = new ArrayList<ITableColumn>();
 213  24
                 if (getClassDescriptor() != null)
 214  
                 {
 215  24
                         LOG.debug("Creating Columns for " + getClassDescriptor().getPluralDisplayName());
 216  100
                         for (IPropertyDescriptor descriptor : getPropertyDescriptors())
 217  
                         {
 218  52
                                 TrailsTableColumn tableColumn = new TrailsTableColumn(descriptor, getEvaluator());
 219  52
                                 tableColumn.loadSettings(getContainer());
 220  52
                                 columns.add(tableColumn);
 221  104
                                 Block block = (Block) getContainer().getComponents().get(
 222  52
                                                 descriptor.getName() + AbstractTableColumn.VALUE_RENDERER_BLOCK_SUFFIX);
 223  52
                                 if (block == null)
 224  
                                 {
 225  44
                                         if (getLinkProperty().equals(descriptor.getName())
 226  20
                                                         && (getClassDescriptor().isAllowSave() || getClassDescriptor().isAllowRemove()))
 227  
                                         {
 228  
                                                 /**
 229  
                                                  * Add a link for the edit page following these rules:
 230  
                                                  * a) Use the identifier descriptor if is displayable (summary=true ).
 231  
                                                  * b) Use the first displayable property if  the identifier property is not displayable
 232  
                                                  *    (summary=false)
 233  
                                                  *
 234  
                                                  */
 235  20
                                                 Block linkBlock = (Block) getContainer().getComponents().get(LINK_COLUMN);
 236  40
                                                 tableColumn.setValueRendererSource(new BlockTableRendererSource(
 237  20
                                                                 linkBlock != null ? linkBlock : (Block) getComponent(LINK_COLUMN)));
 238  
                                         } else
 239  
                                         {
 240  24
                                                 alterTableColumn(descriptor, tableColumn);
 241  
                                         }
 242  
                                 }
 243  
                         }
 244  24
                         if (getExtraColumns() != null)
 245  
                         {
 246  0
                                 addAll(columns, getTableColumnModel().getColumns());
 247  
                         }
 248  
                 } else
 249  
                 {
 250  0
                         LOG.warn("NULL ClassDescriptor");
 251  
                 }
 252  24
                 return columns;
 253  
         }
 254  
 
 255  
         /**
 256  
          * Hook method to allow subclasses to modify the tableColumn,
 257  
          *
 258  
          * @param descriptor
 259  
          * @param tableColumn
 260  
          */
 261  
         protected void alterTableColumn(IPropertyDescriptor descriptor, TrailsTableColumn tableColumn)
 262  
         {
 263  
 
 264  24
         }
 265  
 
 266  
         protected boolean shouldDisplay(IPropertyDescriptor descriptor)
 267  
         {
 268  240
                 return !descriptor.isHidden() && descriptor.isSummary() &&
 269  120
                                 ((descriptor.isCollection() && isShowCollections()) || (!descriptor.isCollection()));
 270  
         }
 271  
 
 272  
         /**
 273  
          * @return
 274  
          */
 275  
         public String getIdentifierProperty()
 276  
         {
 277  4
                 return this.getIdentifierPropertyDescriptor().getName();
 278  
 
 279  
         }
 280  
 
 281  
         /**
 282  
          * Returns the name of the property to be used as link to the editor. If the default Id property is not displayable
 283  
          * then return the name of the first displayable property.
 284  
          *
 285  
          * @return
 286  
          */
 287  
         public String getLinkProperty()
 288  
         {
 289  44
                 IPropertyDescriptor propertyDescriptor = getIdentifierPropertyDescriptor();
 290  44
                 if (!shouldDisplay(propertyDescriptor))
 291  0
                         propertyDescriptor = getFirstDisplayableProperty();
 292  
 
 293  44
                 return propertyDescriptor.getName();
 294  
         }
 295  
 
 296  
         /**
 297  
          * Returns the first displayable property.
 298  
          *
 299  
          * @return
 300  
          */
 301  
         protected IPropertyDescriptor getFirstDisplayableProperty()
 302  
         {
 303  0
                 for (IPropertyDescriptor descriptor : getPropertyDescriptors())
 304  
                 {
 305  0
                         if (shouldDisplay(descriptor))
 306  
                         {
 307  0
                                 return descriptor;
 308  
 
 309  
                         }
 310  
                 }
 311  
 
 312  0
                 return null; // If we get here, that means we have no displayable descriptors
 313  
                 // TODO check if we should throw an exception instead
 314  
         }
 315  
 
 316  
         /**
 317  
          * @return
 318  
          */
 319  
         protected IPropertyDescriptor getIdentifierPropertyDescriptor()
 320  
         {
 321  48
                 return (IPropertyDescriptor) getClassDescriptor().getIdentifierDescriptor();
 322  
 
 323  
         }
 324  
 
 325  
         /**
 326  
          * It provides the source parameter to the inner [<a href="http://tapestry.apache.org/tapestry4.1/tapestry-contrib/componentreference/table.html">table
 327  
          * </a>]
 328  
          *
 329  
          * @return The data to be displayed by the inner table.
 330  
          */
 331  
         public Object getSource()
 332  
         {
 333  0
                 return getInstances();
 334  
         }
 335  
 
 336  
         /**
 337  
          * Returns the table column model as specified by the 'columns' binding. If the value of the 'columns' binding is of a
 338  
          * type different than ITableColumnModel, this method makes the appropriate conversion.
 339  
          *
 340  
          * @return The table column model as specified by the 'columns' binding
 341  
          */
 342  
         protected ITableColumnModel getTableColumnModel()
 343  
         {
 344  0
                 Object objColumns = getExtraColumns();
 345  
 
 346  0
                 if (objColumns == null) return null;
 347  
 
 348  0
                 if (objColumns instanceof ITableColumnModel)
 349  
                 {
 350  0
                         return (ITableColumnModel) objColumns;
 351  
                 }
 352  
 
 353  0
                 if (objColumns instanceof Iterator)
 354  
                 {
 355  
                         // convert to List
 356  0
                         Iterator objColumnsIterator = (Iterator) objColumns;
 357  0
                         List arrColumnsList = new ArrayList();
 358  0
                         addAll(arrColumnsList, objColumnsIterator);
 359  0
                         objColumns = arrColumnsList;
 360  
                 }
 361  
 
 362  0
                 if (objColumns instanceof List)
 363  
                 {
 364  
                         // validate that the list contains only ITableColumn instances
 365  0
                         List arrColumnsList = (List) objColumns;
 366  0
                         int nColumnsNumber = arrColumnsList.size();
 367  0
                         for (int i = 0; i < nColumnsNumber; i++)
 368  
                         {
 369  0
                                 if (!(arrColumnsList.get(i) instanceof ITableColumn))
 370  0
                                         throw new ApplicationRuntimeException(columnsOnlyPlease(this));
 371  
                         }
 372  
                         // objColumns = arrColumnsList.toArray(new
 373  
                         // ITableColumn[nColumnsNumber]);
 374  0
                         return new SimpleTableColumnModel(arrColumnsList);
 375  
                 }
 376  
 
 377  0
                 if (objColumns instanceof ITableColumn[])
 378  
                 {
 379  0
                         return new SimpleTableColumnModel(
 380  0
                                         (ITableColumn[]) objColumns);
 381  
                 }
 382  
 
 383  0
                 if (objColumns instanceof String)
 384  
                 {
 385  0
                         String strColumns = (String) objColumns;
 386  0
                         if (getBinding("extraColumns").isInvariant())
 387  
                         {
 388  
                                 // if the binding is invariant, create the columns only once
 389  0
                                 if (m_objColumnModel == null)
 390  0
                                         m_objColumnModel = generateTableColumnModel(strColumns);
 391  0
                                 return m_objColumnModel;
 392  
                         }
 393  
 
 394  
                         // if the binding is not invariant, create them every time
 395  0
                         return generateTableColumnModel(strColumns);
 396  
                 }
 397  0
                 throw new ApplicationRuntimeException(invalidTableColumns(this, objColumns));
 398  
         }
 399  
 
 400  
         /**
 401  
          * Generate a table column model out of the description string provided. Entries in the description string are
 402  
          * separated by commas. Each column entry is of the format name, name:expression, or name:displayName:expression. An
 403  
          * entry prefixed with ! represents a non-sortable column. If the whole description string is prefixed with *, it
 404  
          * represents columns to be included in a Form.
 405  
          *
 406  
          * @param strDesc the description of the column model to be generated
 407  
          * @return a table column model based on the provided description
 408  
          */
 409  
         protected ITableColumnModel generateTableColumnModel(String strDesc)
 410  
         {
 411  0
                 return getTableViewComponent().getModelSource().generateTableColumnModel(
 412  0
                                 getTableViewComponent().getColumnSource(), strDesc, getTableViewComponent(), getContainer());
 413  
         }
 414  
 
 415  
         private void addAll(List arrColumnsList, Iterator objColumnsIterator)
 416  
         {
 417  0
                 while (objColumnsIterator.hasNext())
 418  0
                         arrColumnsList.add(objColumnsIterator.next());
 419  0
         }
 420  
 
 421  
         protected TableView getTableViewComponent()
 422  
         {
 423  0
                 return (TableView) getComponent("table").getComponent("tableView");
 424  
         }
 425  
 
 426  4
         private static final MessageFormatter _formatter = new MessageFormatter(TableMessages.class);
 427  
 
 428  
         static String columnsOnlyPlease(IComponent component)
 429  
         {
 430  0
                 return _formatter.format("columns-only-please", component.getExtendedId());
 431  
         }
 432  
 
 433  
         static String invalidTableColumns(IComponent component, Object columnSource)
 434  
         {
 435  0
                 return _formatter.format("invalid-table-column", component.getExtendedId(),
 436  0
                                 ClassFabUtils.getJavaClassName(columnSource.getClass()));
 437  
         }
 438  
 
 439  
 /*
 440  
         // there are still issues with inherited binding.
 441  
         @Component(id = "table", type = "contrib:Table", inheritInformalParameters = true,
 442  
                         bindings = {"row=object",
 443  
                                         "rowsClass=rowsClass",
 444  
                                         "column=column",
 445  
                                         "columnsClass=columnsClass",
 446  
                                         "index=index",
 447  
                                         "source=source",
 448  
                                         "columns=columns",
 449  
                                         "pageSize=pageSize",
 450  
                                         "initialSortColumn=initialSortColumn",
 451  
                                         "initialSortOrder=initialSortOrder",
 452  
                                         "persist=persist"})
 453  
         public abstract Table getTable();
 454  
 */
 455  
 
 456  
 
 457  
 }