1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 package org.apache.myfaces.component.html.ext; 20 21 import javax.faces.model.DataModel; 22 import javax.faces.model.DataModelEvent; 23 import javax.faces.model.DataModelListener; 24 import java.io.Serializable; 25 import java.util.ArrayList; 26 import java.util.List; 27 28 /** 29 * Provide a serializable equivalent of the standard DataModel classes. 30 * <p> 31 * The standard JSF UIData components accept a DataModel as the "value" for 32 * the ordered sequence of objects to be rendered in the table. Various 33 * types (List, array, ResultSet) are also accepted and automatically 34 * wrapped in one of the standard DataModel classes. 35 * <p> 36 * The standard DataModel classes are not Serializable by default, because 37 * there is no state in the class which needs to be preserved between render 38 * and postback. And the standard UIData components don't serialize the 39 * data model object, just the EL expression for the "value" attribute; the 40 * data itself is refetched when needed by re-evaluating the EL expression. 41 * <p> 42 * However there can be good reasons to serialize the list of data that is 43 * <i>wrapped</i> by the DataModel along with the UIData component. For these 44 * cases, the tomahawk t:dataTable component offers a "preserveDataModel" flag 45 * that will automatically serialize the data model along with the 46 * HtmlDataTable component; it does this by invoking the "value" binding of 47 * the t:dataTable then creating an instance of this class or one of its 48 * subclasses instead of the standard JSF DataModels. 49 * <p> 50 * This class performs two roles. It is the base implementation for specialised 51 * classes that wrap various datatypes that can be returned from the table's 52 * "value" binding. It also implements the case where the value object 53 * returned is of type DataModel. 54 * <p> 55 * When the UIData's "value" binding returns a DataModel instance, this class 56 * extracts each rowData object from the wrapped data of the original 57 * DataModel and adds these objects to an instance of this class which 58 * <i>is</i> Serializable. Of course the rowdata objects must be serializable 59 * for this to work. As a side-effect, however, the original DataModel object 60 * will be discarded, and replaced by an instance of this class. This means 61 * that any special optimisations or behaviour of the concrete DataModel 62 * subclass will be lost. 63 * 64 * @author Manfred Geiler (latest modification by $Author: grantsmith $) 65 * @version $Revision: 472630 $ $Date: 2006-11-08 15:40:03 -0500 (Wed, 08 Nov 2006) $ 66 */ 67 class _SerializableDataModel 68 extends DataModel 69 implements Serializable 70 { 71 private static final long serialVersionUID = -3511848078295893064L; 72 //private static final Log log = LogFactory.getLog(_SerializableDataModel.class); 73 protected int _first; 74 protected int _rows; 75 protected int _rowCount; 76 protected List _list; 77 private transient int _rowIndex = -1; 78 79 public _SerializableDataModel(int first, int rows, DataModel dataModel) 80 { 81 _first = first; 82 _rows = rows; 83 _rowCount = dataModel.getRowCount(); 84 if (_rows <= 0) 85 { 86 _rows = _rowCount - first; 87 } 88 _list = new ArrayList(rows); 89 for (int i = 0; i < _rows; i++) 90 { 91 dataModel.setRowIndex(_first + i); 92 if (!dataModel.isRowAvailable()) break; 93 _list.add(dataModel.getRowData()); 94 } 95 _rowIndex = -1; 96 97 DataModelListener[] dataModelListeners = dataModel.getDataModelListeners(); 98 for (int i = 0; i < dataModelListeners.length; i++) 99 { 100 DataModelListener dataModelListener = dataModelListeners[i]; 101 addDataModelListener(dataModelListener); 102 } 103 } 104 105 protected _SerializableDataModel() 106 { 107 } 108 109 public int getFirst() 110 { 111 return _first; 112 } 113 114 public void setFirst(int first) 115 { 116 _first = first; 117 } 118 119 public int getRows() 120 { 121 return _rows; 122 } 123 124 public void setRows(int rows) 125 { 126 _rows = rows; 127 } 128 129 public boolean isRowAvailable() 130 { 131 return _rowIndex >= _first && 132 _rowIndex < _first + _rows && 133 _rowIndex < _rowCount && 134 _list.size() > _rowIndex - _first; 135 } 136 137 public int getRowCount() 138 { 139 return _rowCount; 140 } 141 142 public Object getRowData() 143 { 144 if (!isRowAvailable()) 145 { 146 throw new IllegalStateException("row not available"); 147 } 148 return _list.get(_rowIndex - _first); 149 } 150 151 public int getRowIndex() 152 { 153 return _rowIndex; 154 } 155 156 public void setRowIndex(int rowIndex) 157 { 158 if (rowIndex < -1) 159 { 160 throw new IllegalArgumentException(); 161 } 162 163 int oldRowIndex = _rowIndex; 164 _rowIndex = rowIndex; 165 if (oldRowIndex != _rowIndex) 166 { 167 Object data = isRowAvailable() ? getRowData() : null; 168 DataModelEvent event = new DataModelEvent(this, _rowIndex, data); 169 DataModelListener[] listeners = getDataModelListeners(); 170 for (int i = 0; i < listeners.length; i++) 171 { 172 listeners[i].rowSelected(event); 173 } 174 } 175 } 176 177 public Object getWrappedData() 178 { 179 return _list; 180 } 181 182 public void setWrappedData(Object obj) 183 { 184 if (obj != null) 185 { 186 throw new IllegalArgumentException("Cannot set wrapped data of _SerializableDataModel"); 187 } 188 } 189 190 191 192 /* 193 // StateHolder interface 194 195 public Object saveState(FacesContext context) 196 { 197 Object values[] = new Object[4]; 198 values[0] = new Integer(_first); 199 values[1] = new Integer(_rows); 200 values[2] = new Integer(_rowCount); 201 values[3] = _list; 202 return ((Object) (values)); 203 } 204 205 public void restoreState(FacesContext context, Object state) 206 { 207 Object values[] = (Object[])state; 208 _first = ((Integer)values[0]).intValue(); 209 _rows = ((Integer)values[1]).intValue(); 210 _rowCount = ((Integer)values[2]).intValue(); 211 _list = (List)values[3]; 212 } 213 214 public boolean isTransient() 215 { 216 return false; 217 } 218 219 public void setTransient(boolean newTransientValue) 220 { 221 throw new UnsupportedOperationException(); 222 } 223 */ 224 }