View Javadoc

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 }