1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.myfaces.component.html.ext;
21
22 import java.sql.ResultSet;
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.Collections;
26 import java.util.Comparator;
27 import java.util.List;
28
29 import javax.faces.model.ArrayDataModel;
30 import javax.faces.model.DataModel;
31 import javax.faces.model.ListDataModel;
32 import javax.faces.model.ResultDataModel;
33 import javax.faces.model.ResultSetDataModel;
34 import javax.faces.model.ScalarDataModel;
35 import javax.servlet.jsp.jstl.sql.Result;
36
37
38
39
40
41
42
43 public class BaseSortableModel extends DataModel
44 {
45 private static final Class OBJECT_ARRAY_CLASS = (new Object[0]).getClass();
46
47 protected DataModel _model = null;
48 private Object _wrappedData = null;
49
50 private IntList _sortedIndicesList = null,
51 _baseIndicesList = null;
52
53 private Comparator _comparator = null;
54
55
56 public Comparator getComparator() {
57 return _comparator;
58 }
59
60 public void setComparator(Comparator comparator) {
61 this._comparator = comparator;
62 sort();
63 }
64
65
66
67
68
69
70 public BaseSortableModel(Object model)
71 {
72 setWrappedData(model);
73 }
74
75
76
77
78
79 public BaseSortableModel(){}
80
81 public Object getRowData()
82 {
83 return _model.getRowData();
84 }
85
86 public Object getWrappedData()
87 {
88 return _wrappedData;
89 }
90
91 public boolean isRowAvailable()
92 {
93 return _model.isRowAvailable();
94 }
95
96
97
98
99
100
101 public void setWrappedData(Object data)
102 {
103 _baseIndicesList = null;
104 _model = toDataModel(data);
105 _sortedIndicesList = null;
106 _wrappedData = data;
107 }
108
109 protected DataModel toDataModel(Object data)
110 {
111 if (data == null)
112 {
113 return EMPTY_DATA_MODEL;
114 }
115 else if (data instanceof DataModel)
116 {
117 return (DataModel) data;
118 }
119 else if (data instanceof List)
120 {
121 return new ListDataModel((List) data);
122 }
123
124 else if (data instanceof Collection)
125 {
126 return new ListDataModel(new ArrayList((Collection) data));
127 }
128 else if (OBJECT_ARRAY_CLASS.isAssignableFrom(data.getClass()))
129 {
130 return new ArrayDataModel((Object[]) data);
131 }
132 else if (data instanceof ResultSet)
133 {
134 return new ResultSetDataModel((ResultSet) data);
135 }
136 else if (data instanceof Result)
137 {
138 return new ResultDataModel((Result) data);
139 }
140 else
141 {
142 return new ScalarDataModel(data);
143 }
144 }
145
146 public int getRowCount()
147 {
148 return _model.getRowCount();
149 }
150
151 public void setRowIndex(int rowIndex)
152 {
153 int baseIndex = _toBaseIndex(rowIndex);
154 _model.setRowIndex(baseIndex);
155 }
156
157 public int getRowIndex()
158 {
159 int baseIndex = _model.getRowIndex();
160 return _toSortedIndex(baseIndex);
161 }
162
163 public String toString()
164 {
165 return "BaseSortableModel[" + _model + "]";
166 }
167
168
169
170
171
172 public void sort()
173 {
174 Comparator comparator = getComparator();
175 if (null == comparator)
176 {
177
178 _baseIndicesList = _sortedIndicesList = null;
179 return;
180 }
181
182
183 int sz = getRowCount();
184 if ((_baseIndicesList == null) || (_baseIndicesList.size() != sz))
185 {
186
187
188
189
190
191
192 _baseIndicesList = new IntList(sz);
193 }
194
195 final int rowIndex = _model.getRowIndex();
196
197 _model.setRowIndex(0);
198
199 if (_model.isRowAvailable())
200 {
201 Collections.sort(_baseIndicesList, new RowDataComparator(comparator, _model));
202 _sortedIndicesList = null;
203 }
204
205 _model.setRowIndex(rowIndex);
206 }
207
208 private int _toSortedIndex(int baseIndex)
209 {
210 if ((_sortedIndicesList == null) && (_baseIndicesList != null))
211 {
212 _sortedIndicesList = (IntList) _baseIndicesList.clone();
213 for(int i=0; i<_baseIndicesList.size(); i++)
214 {
215 Integer base = (Integer) _baseIndicesList.get(i);
216 _sortedIndicesList.set(base.intValue(), new Integer(i));
217 }
218 }
219
220 return _convertIndex(baseIndex, _sortedIndicesList);
221 }
222
223 private int _toBaseIndex(int sortedIndex)
224 {
225 return _convertIndex(sortedIndex, _baseIndicesList);
226 }
227
228 private int _convertIndex(int index, List indices)
229 {
230 if (index < 0)
231 return index;
232
233 if ((indices != null) && (indices.size() > index))
234 {
235 index = ((Integer) indices.get(index)).intValue();
236 }
237 return index;
238 }
239
240 private static final class IntList extends ArrayList implements Cloneable
241 {
242 public IntList(int size)
243 {
244 super(size);
245 _expandToSize(size);
246 }
247
248 private void _expandToSize(int desiredSize)
249 {
250 for(int i=0; i<desiredSize; i++)
251 add(new Integer(i));
252 }
253 }
254
255 protected static class RowDataComparator implements Comparator
256 {
257 private Comparator dataComparator = null;
258 private DataModel dataModel = null;
259
260 public RowDataComparator(Comparator comparator, DataModel model)
261 {
262 this.dataComparator = comparator;
263 this.dataModel = model;
264 }
265
266 public int compare(Object arg1, Object arg2) {
267 Integer r1 = (Integer)arg1;
268 Integer r2 = (Integer)arg2;
269 dataModel.setRowIndex(r1.intValue());
270 Object rowData1 = dataModel.getRowData();
271 dataModel.setRowIndex(r2.intValue());
272 Object rowData2 = dataModel.getRowData();
273
274 return dataComparator.compare(rowData1, rowData2);
275 }
276 }
277
278 private static final DataModel EMPTY_DATA_MODEL = new _SerializableDataModel()
279 {
280 public boolean isRowAvailable()
281 {
282 return false;
283 }
284
285 public int getRowCount()
286 {
287 return 0;
288 }
289
290 public Object getRowData()
291 {
292 throw new IllegalArgumentException();
293 }
294
295 public int getRowIndex()
296 {
297 return -1;
298 }
299
300 public void setRowIndex(int i)
301 {
302 if (i < -1)
303 throw new IndexOutOfBoundsException("Index < 0 : " + i);
304 }
305
306 public Object getWrappedData()
307 {
308 return null;
309 }
310
311 public void setWrappedData(Object obj)
312 {
313 if (obj == null)
314 return;
315 throw new UnsupportedOperationException(this.getClass().getName()
316 + " UnsupportedOperationException");
317 }
318 };
319 }