Plugable RowSorter Patch:
I can't get to the cvs repository from work, so I made
diffs in another tool. I've included two diffs and an
interface.
If the mail system eats the files I'll find another
way to send them.
Aaron
--- Matt Raible <[EMAIL PROTECTED]> wrote:
> These enhancements sound great. Fabrizio - what do
> you think about
> adding them? Send patches!!
>
> Matt
>
> > -----Original Message-----
> > From: [EMAIL PROTECTED]
>
> >
>
[mailto:[EMAIL PROTECTED]
> On
> > Behalf Of Aaron Smuts
> > Sent: Monday, May 24, 2004 9:54 PM
> > To: [EMAIL PROTECTED]
> > Subject: [displaytag-devel] avoiding unecessary
> iterations--runSimple
> >
> >
> > Problem:
> > Large lists of objects are iterated pointlessly
> for
> > most uses of display tag. Except for on the first
> > iteration, the CulumnTag methods do almost nothing
> if
> > you specify the property for a column. Most of
> the
> > time and empty cell is added toa Row and the Row
> > added to the Table Model. However, adding a row
> to
> > the table is unnecesary for most purposes, as we
> shall
> > see. The typically unncessary iterations result
> in
> > numerous method calls that dramatically hurt
> > performance.
> >
> > The sample paging jsp's only use a few
> columns--about
> > 4. If you add a colum the number of additional
> method
> > calls is multiplied by the number of rows for each
> > column. Add 8 columns and a simple paging example
> > that displays only 10 rows of a list of 2000 can
> take
> > over 2 seconds of iteration time and then only
> 15-30
> > millis of real work in the TableTag doEndTag
> method.
> > This makes the run time of display tag
> exponential.
> >
> >
> > Solution:
> > I wanted to skip the iterations and do only the
> work
> > required. I was able to do this and get the time
> to
> > nearly O(1), on non sorts. (There is still some
> > iteration on building the partial list, so it is
> > probably really O(N), but that iteration is
> > negligible. Sorting is merge sort time. )
> >
> > To do this I did a couple of things.
> >
> > 1. If the pageSize is greater than zero, I return
> > SKIP_BODY from TableTag doAfterBody. I did it
> here to
> > let the first colum iteration take place for
> building
> > header. (The condition to skip should take into
> > account more options, however.)
> >
> > 2. I pass the original list of data to
> TableModel.
> > Then, if there is paging, in getViewable data of
> > TableTag, I build up the rows of the TableModel
> that I
> > want to use based on what is left of the orignal
> list
> > after pulling out the chunk for the page.
> >
> > 3. If there is a sort, I made the RowSorter
> > Implementation able to handle any object and not
> just
> > a Row, so I can pass it the original list and not
> the
> > Row wrapped list. This was easy. I just set
> object1
> > = obj1 (the method param). The ability to do this
> is
> > key, since it makes the initial iteration largely
> > unnecessary.
> >
> > Also, with the RowSorter enhancement, I was able
> to
> > skip decoration for sorts. Another great boost.
> >
> >
> > Result:
> > With the plugable RowSorter enhancement and the
> > runSimple changes I was able to sort without
> > reflection. The total work takes about 16-30
> millis
> > for a list of 2000 items with 8 columns, whereas
> > before it took 2 1/2 seconds.
> >
> > This makes display tag usable for very large
> result
> > sets.
> >
> > I'm not sure what features will be unavailable
> with
> > this enhancement. My proposed option should be
> > configurable by setting a property like
> runSimple=true
> > or something on the table. Also the condition to
> > skip_body should take into account more that just
> > whether or not the list can be paged.
> >
> > I may have left out a few details, but it works
> great
> > for probably 99% of what anyone will do with the
> > library. It should be an option to runSimple or
> > something similar, since you can get a 200X
> > performance boost at modest conditions.
> >
> > I'll submit patches if there are no obvious
> drawbacks.
> >
> > Cheers,
> >
> > Aaron Smuts
> > http://jakarta.apache.org/turbine/jcs/
> >
> >
> >
> >
> >
> > __________________________________
> > Do you Yahoo!?
> > Friends. Fun. Try the all-new Yahoo! Messenger.
> http://messenger.yahoo.com/
>
>
>
-------------------------------------------------------
> This SF.Net email is sponsored by: Oracle 10g
> Get certified on the hottest thing ever to hit the
> market... Oracle 10g.
>
> Take an Oracle 10g class now, and we'll give you the
> exam FREE.
>
http://ads.osdn.com/?ad_id=3149&alloc_id=8166&op=click
> _______________________________________________
> displaytag-devel mailing list
> [EMAIL PROTECTED]
>
https://lists.sourceforge.net/lists/listinfo/displaytag-devel
>
>
>
>
>
-------------------------------------------------------
> This SF.Net email is sponsored by: Oracle 10g
> Get certified on the hottest thing ever to hit the
> market... Oracle 10g.
> Take an Oracle 10g class now, and we'll give you the
> exam FREE.
>
http://ads.osdn.com/?ad_id=3149&alloc_id=8166&op=click
> _______________________________________________
> displaytag-devel mailing list
> [EMAIL PROTECTED]
>
https://lists.sourceforge.net/lists/listinfo/displaytag-devel
__________________________________
Do you Yahoo!?
Friends. Fun. Try the all-new Yahoo! Messenger.
http://messenger.yahoo.com/
Title: Guiffy Together Differences
1 1 package org.displaytag.model;
2 2
3 3 import java.util.Comparator;
4 4
5 5 import org.apache.commons.lang.builder.EqualsBuilder;
6 6 import org.apache.commons.lang.builder.HashCodeBuilder;
7 7 import org.displaytag.decorator.TableDecorator;
8 8 import org.displaytag.exception.ObjectLookupException;
9 9 import org.displaytag.exception.RuntimeLookupException;
10 10 import org.displaytag.util.LookupUtil;
11 11
12 12
13 13 /**
14 14 * Comparator for rows.
15 15 * @author Fabrizio Giustina
16 16 * @version $Revision $ ($Author $)
17 17 */
18 <public class RowSorterImpl implements Comparator
18>public class RowSorter implements Comparator
19 19 {
20 20
21 21 /**
22 22 * name of the property in bean.
23 23 */
24 24 private String property;
25 25
26 26 /**
27 27 * table decorator.
28 28 */
29 29 private TableDecorator decorator;
30 30
31 31 /**
32 32 * sort order ascending?
33 33 */
34 34 private boolean ascending;
35 35
36 36 /**
37 37 * Index of the sorted column.
38 38 */
39 39 private int columnIndex;
40 40
41 41 /**
42 42 * Initialize a new RowSorter.
43 43 * @param sortedColumnIndex index of the sorted column
44 44 * @param beanProperty name of the property. If pProperty is null column index is used to get a static cell value
45 45 * from the row object
46 46 * @param tableDecorator TableDecorator instance
47 47 * @param ascendingOrder boolean ascending order?
48 48 */
49 < public RowSorterImpl(int sortedColumnIndex, String beanProperty, TableDecorator tableDecorator, boolean ascendingOrder)
49> public RowSorter(int sortedColumnIndex, String beanProperty, TableDecorator tableDecorator, boolean ascendingOrder)
50 50 {
51 51 this.columnIndex = sortedColumnIndex;
52 52 this.property = beanProperty;
53 53 this.decorator = tableDecorator;
54 54 this.ascending = ascendingOrder;
55 55 }
56 56
57 57 /**
58 58 * Compares two objects by first fetching a property from each object and then comparing that value. If there are
59 59 * any errors produced while trying to compare these objects then a RunTimeException will be thrown as any error
60 60 * found here will most likely be a programming error that needs to be quickly addressed (like trying to compare
61 61 * objects that are not comparable, or trying to read a property from a bean that is invalid, etc...)
62 62 * @param object1 Object
63 63 * @param object2 Object
64 64 * @return int
65 65 * @see java.util.Comparator#compare(Object, Object)
66 66 */
67 67 public final int compare(Object object1, Object object2)
68 68 {
69 69
70 < // Should be able to handle sorting objects that are not wrapped in Rows
71 < Object obj1 = object1;
72 < Object obj2 = object2;
70> Object obj1 = null;
71> Object obj2 = null;
73 72
74 73 // if property is null compare using two static cell objects
75 74 if (this.property == null)
76 75 {
77 76 if (object1 instanceof Row)
78 77 {
79 78 obj1 = ((Row) object1).getCellList().get(this.columnIndex);
80 79 }
81 80 if (object2 instanceof Row)
82 81 {
83 82 obj2 = ((Row) object2).getCellList().get(this.columnIndex);
84 83 }
85 84
86 85 return checkNullsAndCompare(obj1, obj2);
87 86
88 87 }
89 88 else
90 89 {
91 90 if (object1 instanceof Row)
92 91 {
93 92 obj1 = ((Row) object1).getObject();
94 93 }
95 94 if (object2 instanceof Row)
96 95 {
97 96 obj2 = ((Row) object2).getObject();
98 97 }
99 98
100 99 try
101 100 {
102 101 Object result1 = null;
103 102 Object result2 = null;
104 103
105 104 // If they have supplied a decorator, then make sure and use it for the sorting as well
106 105 if (this.decorator != null && this.decorator.hasGetterFor(this.property))
107 106 {
108 107 // set the row before sending to the decorator
109 108 this.decorator.initRow(obj1, 0, 0);
110 109
111 110 result1 = LookupUtil.getBeanProperty(this.decorator, this.property);
112 111
113 112 // set the row before sending to the decorator
114 113 this.decorator.initRow(obj2, 0, 0);
115 114
116 115 result2 = LookupUtil.getBeanProperty(this.decorator, this.property);
117 116 }
118 117 else
119 118 {
120 119 result1 = LookupUtil.getBeanProperty(obj1, this.property);
121 120 result2 = LookupUtil.getBeanProperty(obj2, this.property);
122 121 }
123 122
124 123 return checkNullsAndCompare(result1, result2);
125 124 }
126 125 catch (ObjectLookupException e)
127 126 {
128 127 throw new RuntimeLookupException(getClass(), this.property, e);
129 128 }
130 129 }
131 130 }
132 131
133 132 /**
134 133 * Compares two given objects handlig nulls and not comparable objects are handled. Not comparable objects are
135 134 * compared using their string representation.
136 135 * @param object1 first object to compare
137 136 * @param object2 second object to compare
138 137 * @return int result
139 138 */
140 139 private int checkNullsAndCompare(Object object1, Object object2)
141 140 {
142 141 int returnValue = 0;
143 142
144 143 if (object1 instanceof Comparable && object2 instanceof Comparable)
145 144 {
146 145 returnValue = ((Comparable) object1).compareTo(object2);
147 146 }
148 147 else if (object1 == null && object2 == null)
149 148 {
150 149 returnValue = 0;
151 150 }
152 151 else if (object1 == null && object2 != null)
153 152 {
154 153 returnValue = 1;
155 154 }
156 155 else if (object1 != null && object2 == null)
157 156 {
158 157 returnValue = -1;
159 158 }
160 159 else
161 160 {
162 161 // if object are not null and don't implement comparable, compare using string values
163 162 returnValue = object1.toString().compareTo(object2.toString());
164 163 }
165 164
166 165 int ascendingInt = this.ascending ? 1 : -1;
167 166 return ascendingInt * returnValue;
168 167 }
169 168
170 169 /**
171 170 * Is this Comparator the same as another one?
172 171 * @param object Object
173 172 * @return boolean
174 173 * @see java.util.Comparator#equals(Object)
175 174 */
176 175 public final boolean equals(Object object)
177 176 {
178 < if (object instanceof RowSorterImpl)
177> if (object instanceof RowSorter)
179 178 {
180 < return new EqualsBuilder().append(this.property, ((RowSorterImpl) object).property).append(this.columnIndex,
181 < ((RowSorterImpl) object).columnIndex).isEquals();
179> return new EqualsBuilder().append(this.property, ((RowSorter) object).property).append(this.columnIndex,
180> ((RowSorter) object).columnIndex).isEquals();
182 181 }
183 182
184 183 return false;
185 184 }
186 185
187 186 /**
188 187 * @see java.lang.Object#hashCode()
189 188 */
190 189 public final int hashCode()
191 190 {
192 191 return new HashCodeBuilder(31, 33).append(this.property).append(this.columnIndex).toHashCode();
193 192 }
194 193
195 194 }
|
Title: Guiffy Together Differences
1 1 package org.displaytag.model;
2 2
3 3 import java.util.ArrayList;
4 4 import java.util.Collections;
5 5 import java.util.List;
6 6
7 7 import org.apache.commons.logging.Log;
8 8 import org.apache.commons.logging.LogFactory;
9 9 import org.displaytag.decorator.TableDecorator;
10 10 import org.displaytag.properties.TableProperties;
11 11
12 12
13 13 /**
14 14 * @author Fabrizio Giustina
15 15 * @version $Revision: 1.10 $ ($Author: fgiust $)
16 16 */
17 17 public class TableModel
18 18 {
19 19
20 20 /**
21 21 * logger.
22 22 */
23 23 private static Log log = LogFactory.getLog(TableModel.class);
24 24
25 25 /**
26 26 * list of HeaderCell.
27 27 */
28 28 private List headerCellList;
29 29
30 30 /**
31 31 * full list (contains Row objects).
32 32 */
33 33 private List rowListFull;
34 34
35 35 /**
36 36 * list of data to be displayed in page.
37 37 */
38 38 private List rowListPage;
39 39
40 40 /**
41 41 * sort order = ascending?
42 42 */
43 43 private boolean sortOrderAscending = true;
44 44
45 45 /**
46 46 * sort full List? (false sort only displayed page).
47 47 */
48 48 private boolean sortFullTable = true;
49 49
50 50 /**
51 < * Allows for substitution of row sorter classes.
52 < */
53 < private boolean isSortDecorated = false;
54 <
55 < /**
56 < * Allows for substitution of row sorter classes.
57 < */
58 < private String rowSorterClassname = "org.displaytag.model.RowSorterImpl";
59 <
60 < /**
61 51 * index of the sorted column (-1 if the table is not sorted).
62 52 */
63 53 private int sortedColumn = -1;
64 54
65 55 /**
66 56 * Table decorator.
67 57 */
68 58 private TableDecorator tableDecorator;
69 59
70 60 /**
71 61 * id inherited from the TableTag (needed only for logging).
72 62 */
73 63 private String id;
74 64
75 65 /**
76 66 * configurable table properties.
77 67 */
78 68 private TableProperties properties;
79 69
80 70 /**
81 71 * Constructor for TableModel.
82 72 * @param tableProperties table properties
83 73 */
84 74 public TableModel(TableProperties tableProperties)
85 75 {
86 76 this.rowListFull = new ArrayList(20);
87 77 this.headerCellList = new ArrayList(20);
88 78 this.properties = tableProperties;
89 79 }
90 80
91 81 /**
92 82 * Setter for the tablemodel id.
93 83 * @param tableId same id of table tag, needed for logging
94 84 */
95 85 public void setId(String tableId)
96 86 {
97 87 this.id = tableId;
98 88 }
99 89
100 90 /**
101 91 * get the full list.
102 92 * @return the full list containing Row objects
103 93 */
104 94 public List getRowListFull()
105 95 {
106 96 return this.rowListFull;
107 97 }
108 98
109 99 /**
110 100 * gets the partial (paginated) list.
111 101 * @return the partial list to display in page (contains Row objects)
112 102 */
113 103 public List getRowListPage()
114 104 {
115 105 return this.rowListPage;
116 106 }
117 107
118 108 /**
119 109 * adds a Row object to the table.
120 110 * @param row Row
121 111 */
122 112 public void addRow(Row row)
123 113 {
124 114 row.setParentTable(this);
125 115
126 116 if (log.isDebugEnabled())
127 117 {
128 118 log.debug("[" + this.id + "] adding row " + row);
129 119 }
130 120 this.rowListFull.add(row);
131 121 }
132 122
133 123 /**
134 124 * sets the sort full table property. If true the full list is sorted, if false sorting is applied only to the
135 125 * displayed sublist.
136 126 * @param sortFull boolean
137 127 */
138 128 public void setSortFullTable(boolean sortFull)
139 129 {
140 130 this.sortFullTable = sortFull;
141 131 }
142 132
143 133 /**
144 134 * return the sort full table property.
145 135 * @return boolean true if sorting is applied to the full list
146 136 */
147 137 public boolean isSortFullTable()
148 138 {
149 139 return this.sortFullTable;
150 140 }
151 141
152 142 /**
153 143 * return the sort order of the page.
154 144 * @return true if sort order is ascending
155 145 */
156 146 public boolean isSortOrderAscending()
157 147 {
158 148 return this.sortOrderAscending;
159 149
160 150 }
161 151
162 152 /**
163 153 * set the sort order of the list.
164 154 * @param isSortOrderAscending true to sort in ascending order
165 155 */
166 156 public void setSortOrderAscending(boolean isSortOrderAscending)
167 157 {
168 158 this.sortOrderAscending = isSortOrderAscending;
169 159 }
170 160
171 161 /**
172 162 * @param rowList - the new value for this.rowListPage
173 163 */
174 164 public void setRowListPage(List rowList)
175 165 {
176 166 this.rowListPage = rowList;
177 167 }
178 168
179 169 /**
180 170 * getter for the Table Decorator.
181 171 * @return TableDecorator
182 172 */
183 173 public TableDecorator getTableDecorator()
184 174 {
185 175 return this.tableDecorator;
186 176 }
187 177
188 178 /**
189 179 * setter for the table decorator.
190 180 * @param decorator - the TableDecorator object
191 181 */
192 182 public void setTableDecorator(TableDecorator decorator)
193 183 {
194 184 this.tableDecorator = decorator;
195 185 }
196 186
197 187 /**
198 188 * returns true if the table is sorted.
199 189 * @return boolean true if the table is sorted
200 190 */
201 191 public boolean isSorted()
202 192 {
203 193 return this.sortedColumn != -1;
204 194 }
205 195
206 196 /**
207 197 * returns the HeaderCell for the sorted column.
208 198 * @return HeaderCell
209 199 */
210 200 public HeaderCell getSortedColumnHeader()
211 201 {
212 202 if (this.sortedColumn < 0 || (this.sortedColumn > (this.headerCellList.size() - 1)))
213 203 {
214 204 return null;
215 205 }
216 206 return (HeaderCell) this.headerCellList.get(this.sortedColumn);
217 207 }
218 208
219 209 /**
220 210 * return the number of columns in the table.
221 211 * @return int number of columns
222 212 */
223 213 public int getNumberOfColumns()
224 214 {
225 215 return this.headerCellList.size();
226 216 }
227 217
228 218 /**
229 219 * return true is the table has no columns.
230 220 * @return boolean
231 221 */
232 222 public boolean isEmpty()
233 223 {
234 224 return this.headerCellList.size() == 0;
235 225 }
236 226
237 227 /**
238 228 * return the index of the sorted column.
239 229 * @return index of the sorted column or -1 if the table is not sorted
240 230 */
241 231 public int getSortedColumnNumber()
242 232 {
243 233 return this.sortedColumn;
244 234 }
245 235
246 236 /**
247 237 * set the sorted column index.
248 238 * @param sortIndex - the index of the sorted column
249 239 */
250 240 public void setSortedColumnNumber(int sortIndex)
251 241 {
252 242 this.sortedColumn = sortIndex;
253 243 }
254 244
255 245 /**
256 246 * Adds a column header (HeaderCell object).
257 247 * @param headerCell HeaderCell
258 248 */
259 249 public void addColumnHeader(HeaderCell headerCell)
260 250 {
261 251 if (this.sortedColumn == this.headerCellList.size())
262 252 {
263 253 headerCell.setAlreadySorted();
264 254 }
265 255 headerCell.setColumnNumber(this.headerCellList.size());
266 256
267 257 this.headerCellList.add(headerCell);
268 258 }
269 259
270 260 /**
271 261 * List containing headerCell objects.
272 262 * @return List containing headerCell objects
273 263 */
274 264 public List getHeaderCellList()
275 265 {
276 266 return this.headerCellList;
277 267 }
278 268
279 269 /**
280 270 * returns a RowIterator on the requested (full|page) list.
281 271 * @return RowIterator
282 272 * @param full if true returns an iterator on te full list, if false only on the
283 273 * viewable part.
284 274 * @see org.displaytag.model.RowIterator
285 275 */
286 276 public RowIterator getRowIterator(boolean full)
287 277 {
288 278 RowIterator iterator = new RowIterator(
289 279 full ? this.rowListFull : this.rowListPage,
290 280 this.headerCellList,
291 281 this.tableDecorator);
292 282 // copy id for logging
293 283 iterator.setId(this.id);
294 284 return iterator;
295 285 }
296 286
297 287 /**
298 288 * sorts the given list of Rows. The method is called internally by sortFullList() and sortPageList().
299 289 * @param list List
300 290 */
301 291 private void sortRowList(List list)
302 292 {
303 293 if (isSorted())
304 294 {
305 295 HeaderCell sortedHeaderCell = getSortedColumnHeader();
306 296
307 297 if (sortedHeaderCell != null)
308 298 {
309 299 // If it is an explicit value, then sort by that, otherwise sort by the property...
310 300 if (sortedHeaderCell.getBeanPropertyName() != null
311 301 || (this.sortedColumn != -1 && this.sortedColumn < this.headerCellList.size()))
312 302 {
313 < IRowSorter rowSorter = null;
314 < try {
315 < Class rowSorterClass = Class.forName(this.getRowSorterClassname());
316 < rowSorter = (IRowSorter)rowSorterClass.newInstance();
317 < } catch (Exception e) {
318 < throw new IllegalArgumentException(
319 < "\"" + this.getRowSorterClassname() +
320 < "\" is not a valid row sorter class: " + e
321 < );
303> Collections.sort(list, new RowSorter(
304> this.sortedColumn,
305> sortedHeaderCell.getBeanPropertyName(),
306> getTableDecorator(),
307> this.sortOrderAscending));
308> }
309> }
310>
311> }
312>
313> }
314>
315> /**
316> * sort the list displayed in page.
317> */
318> public void sortPageList()
319> {
320> if (log.isDebugEnabled())
321> {
|
IRowSorter.java
Description: IRowSorter.java