KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > blandware > atleap > webapp > taglib > core > grid > RowsIteratorTag


1 /*
2  * Copyright 2004 Blandware (http://www.blandware.com)
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package com.blandware.atleap.webapp.taglib.core.grid;
17
18 import com.blandware.atleap.common.util.PartialCollection;
19 import com.blandware.atleap.common.util.QueryInfo;
20 import com.blandware.atleap.webapp.taglib.core.grid.util.EntityFieldComparator;
21 import com.blandware.atleap.webapp.taglib.core.grid.util.Grid;
22 import com.blandware.atleap.webapp.taglib.core.grid.util.SortField;
23 import com.blandware.atleap.webapp.taglib.core.util.TaglibConstants;
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26 import org.springframework.context.ApplicationContext;
27 import org.springframework.web.context.support.WebApplicationContextUtils;
28
29 import javax.servlet.jsp.JspException JavaDoc;
30 import javax.servlet.jsp.JspTagException JavaDoc;
31 import javax.servlet.jsp.PageContext JavaDoc;
32 import javax.servlet.jsp.tagext.JspFragment JavaDoc;
33 import javax.servlet.jsp.tagext.SimpleTagSupport JavaDoc;
34 import java.io.IOException JavaDoc;
35 import java.lang.reflect.Method JavaDoc;
36 import java.util.*;
37
38 /**
39  * <p>Tag for iterating over rows of grid. Each row represents a piece of data.
40  * <br />
41  * This tag is only valid when nested within <em>grid</em> tag
42  * </p>
43  * <p>
44  * Allowed attributes are:
45  * <ul>
46  * <li>
47  * <b>beanId</b> - identifier of Spring bean to use for getting rows for this
48  * grid
49  * </li>
50  * <li>
51  * <b>method</b> - method of specified bean to call to get collection for
52  * iterating. This method must return instance of
53  * {@link com.blandware.atleap.common.util.PartialCollection} and
54  * accept instance of {@link com.blandware.atleap.common.util.QueryInfo}
55  * as a single argument.
56  * </li>
57  * <li>
58  * <b>collection</b> - collection of objects to display if <b>beanId</b> or <b>method</b> not
59  * specified. Only instances of <cody>java.util.Collection</code>,
60  * </code>java.lang.Object[]</code> and <code>java.util.Map</code> are
61  * supported.
62  * </li>
63  * <li>
64  * <b>tagId</b> - identifier for this iterator tag. It must be unique within
65  * one grid.
66  * </li>
67  * <li>
68  * <b>var</b> - required - name of page-scoped variable to save result of each
69  * iteration under
70  * </li>
71  * <li>
72  * <b>oddClass</b> - CSS class to export when odd row is processed
73  * </li>
74  * <li>
75  * <b>evenClass</b> - CSS class to export when even row is processed
76  * </li>
77  * <li>
78  * <b>firstRowEven</b> - indicates which CSS class to use for first row.
79  * If value is <code>Boolean.TRUE</code> (it is by default) or attribute is
80  * omitted, first row class will be that which is specified in <b>evenClass</b>
81  * attribute.<br />
82  * Note, that if grid has more than one iterator and this one is not the
83  * first, value of this attribute is ignored: evennes will be determined
84  * according to last row number in grid, it depends on iterators which have
85  * already finished their work.
86  * </li>
87  * <li>
88  * <b>cssVar</b> - name of page scope variable to save CSS class for current
89  * row. If not specified, but any of <b>oddClass</b> or <b>evenClass</b> is
90  * specified, this will be <code>TaglibConstants.ROW_CLASS_ATTR</code>.
91  * </li>
92  * <li>
93  * <b>indexId</b> - name of page scope variable to save index of each iteration.
94  * If not specified, this will be <code>TaglibConstants.INDEX_ID_ATTR</code>.
95  * </li>
96  * </ul>
97  * </p>
98  * <p>
99  * Either <b>collection</b> or both <b>beanId</b> and <b>method</b> must be specified.
100  * If <b>beanId</b> and <b>method</b> are specified, collection, over which
101  * iteration will be done, will be obtained invoking <b>method</b> on bean,
102  * which ID is <b>beanId</b>. Else, <b>collection</b> will be used as such
103  * collection.
104  * </p>
105  * <p>
106  * On each iteration, following is done: current row is obtained and exported
107  * to page scope variable which name is specified by <b>var</b>. Then evenness
108  * of current row is computed and corresponding style class is exported to
109  * page scope variable which name is specified by <b>cssVar</b>. After that,
110  * index of current iteration is exported to page scope variable which name is
111  * specified by <b>indexId</b> and, at last, tag body is rendered.
112  * </p>
113  * <p><a HREF="RowsIteratorTag.java.htm"><i>View Source</i></a></p>
114  *
115  * @author Sergey Zubtcovskii <a HREF="mailto:sergey.zubtcovskii@blandware.com">&lt;sergey.zubtcovskii@blandware.com&gt;</a>
116  * @version $Revision: 1.19 $ $Date: 2005/10/12 13:34:57 $
117  * @jsp.tag name="rowsIterator"
118  * body-content="scriptless"
119  * @see com.blandware.atleap.webapp.taglib.core.grid.GridTag
120  */

121 public class RowsIteratorTag extends SimpleTagSupport JavaDoc {
122
123     protected transient final Log log = LogFactory.getLog(RowsIteratorTag.class);
124     protected transient ApplicationContext applicationCtx = null;
125
126     /**
127      * Page context key to check the oddness of first row for this iterator.
128      */

129     public static final String JavaDoc IS_ODD_ROW_KEY = "com.blandware.atleap.webapp.taglib.core.grid.IS_ODD_ROW";
130
131     /**
132      * Identifier of Spring bean to use for getting rows for this grid
133      */

134     protected String JavaDoc beanId;
135
136     /**
137      * Method of specified bean to call to get collection for iterating.
138      * This method must return instance of <code>com.blandware.atleap.common.util.PartialCollection</code> and
139      * accept instance of <code>com.blandware.atleap.common.util.QueryInfo</code> as a single argument.
140      *
141      * @see com.blandware.atleap.common.util.PartialCollection
142      * @see com.blandware.atleap.common.util.QueryInfo
143      */

144     protected String JavaDoc method;
145
146     /**
147      * Collection of objects to display if beanId not specified
148      * Only instances of <cody>java.util.Collection</code>, </code>java.lang.Object[]</code> and <code>java.util.Map</code> are supported
149      */

150     protected Object JavaDoc collection;
151
152     /**
153      * Identifier for this iterator tag. It must be unique within one grid.
154      */

155     protected String JavaDoc tagId;
156
157     /**
158      * Name of page-scoped variable to save result of each iteration under
159      */

160     protected String JavaDoc var;
161
162     /**
163      * CSS class to export when odd row is processed
164      */

165     protected String JavaDoc oddClass = new String JavaDoc();
166
167     /**
168      * CSS class to export when even row is processed
169      */

170     protected String JavaDoc evenClass = new String JavaDoc();
171
172     /**
173      * Indicates which CSS class to use for first row.
174      * If value is <code>Boolean.TRUE</code> (it is by default) or attribute is omitted, first row class will be that which is specified
175      * in <code>evenClass</code> attribute.
176      * Note, if grid has more than one iterator and this one is not the first, value of this attribute is ignored:
177      * evennes will be determined according to last row number in grid, it depends on iterators which have already
178      * finished their work.
179      */

180     protected Boolean JavaDoc firstRowEven = Boolean.TRUE;
181
182     /**
183      * Name of page scope variable to save CSS class under
184      */

185     protected String JavaDoc cssVar;
186
187     /**
188      * Index of each iteration will be saved in page context variable with
189      * this name
190      */

191     protected String JavaDoc indexId;
192
193     /**
194      * Iterator of the elements of this collection, while we are actually
195      * running.
196      */

197     private Iterator rowsIterator = null;
198
199     /**
200      * Flag to check what CSS class must be returned
201      */

202     private boolean isOddRow = true;
203
204
205     /**
206      * Contains number of current iteration
207      */

208     private int loopCount = 0;
209
210     /**
211      * Returns bean ID
212      *
213      * @return bean ID
214      * @see #beanId
215      * @jsp.attribute required="false"
216      * rtexprvalue="true"
217      * type="java.lang.String"
218      * description="Identifier of Spring bean to use for getting rows for this grid"
219      */

220     public String JavaDoc getBeanId() {
221         return beanId;
222     }
223
224     /**
225      * Sets bean ID
226      *
227      * @param beanId bean ID to set
228      * @see #beanId
229      */

230     public void setBeanId(String JavaDoc beanId) {
231         this.beanId = beanId;
232     }
233
234     /**
235      * Returns method used to obtain values from bean
236      *
237      * @return method name
238      * @see #method
239      * @jsp.attribute required="false"
240      * rtexprvalue="true"
241      * type="java.lang.String"
242      * description="Method of specified manager to call to get collection of iterating"
243      */

244     public String JavaDoc getMethod() {
245         return method;
246     }
247
248     /**
249      * Sets method used to obtain values from bean
250      *
251      * @param method method name to set
252      * @see #method
253      */

254     public void setMethod(String JavaDoc method) {
255         this.method = method;
256     }
257
258     /**
259      * Returns Collection to iterate over
260      *
261      * @return collection
262      * @see #collection
263      * @jsp.attribute required="false"
264      * rtexprvalue="true"
265      * type="java.lang.Object"
266      * description="Collection of objects to display if beanId not specified"
267      */

268     public Object JavaDoc getCollection() {
269         return collection;
270     }
271
272     /**
273      * Sets Collection to iterate over
274      *
275      * @param collection collection to set
276      * @see #collection
277      */

278     public void setCollection(Object JavaDoc collection) {
279         this.collection = collection;
280     }
281
282     /**
283      * Returns ID of tag
284      *
285      * @return tag ID
286      * @see #tagId
287      * @jsp.attribute required="false"
288      * rtexprvalue="true"
289      * type="java.lang.String"
290      * description="Identifier for this iterator tag. It must be unique within one grid."
291      */

292     public String JavaDoc getTagId() {
293         return tagId;
294     }
295
296     /**
297      * Sets ID of tag
298      *
299      * @param tagId tag ID to set
300      * @see #tagId
301      */

302     public void setTagId(String JavaDoc tagId) {
303         this.tagId = tagId;
304     }
305
306     /**
307      * Returns name of variable which will accept result of each iteration
308      *
309      * @return variable name
310      * @see #var
311      * @jsp.attribute required="true"
312      * rtexprvalue="false"
313      * type="java.lang.String"
314      * description="Name of page scope variable to save result of each iteration under"
315      */

316     public String JavaDoc getVar() {
317         return var;
318     }
319
320     /**
321      * Sets name of variable which will accept result of each iteration
322      *
323      * @param var variable name to set
324      * @see #var
325      */

326     public void setVar(String JavaDoc var) {
327         this.var = var;
328     }
329
330     /**
331      * Returns CSS class for odd rows
332      *
333      * @return odd rows class
334      * @see #oddClass
335      * @jsp.attribute required="false"
336      * rtexprvalue="true"
337      * type="java.lang.String"
338      * description="CSS class to export when odd row is processed"
339      */

340     public String JavaDoc getOddClass() {
341         return oddClass;
342     }
343
344     /**
345      * Sets CSS class for odd rows
346      *
347      * @param oddClass odd rows class to set
348      * @see #oddClass
349      */

350     public void setOddClass(String JavaDoc oddClass) {
351         this.oddClass = oddClass;
352     }
353
354     /**
355      * Returns CSS class for even rows
356      *
357      * @return even rows class
358      * @see #evenClass
359      * @jsp.attribute required="false"
360      * rtexprvalue="true"
361      * type="java.lang.String"
362      * description="CSS class to export when even row is processed"
363      */

364     public String JavaDoc getEvenClass() {
365         return evenClass;
366     }
367
368     /**
369      * Sets CSS class for even rows
370      *
371      * @param evenClass even rows class
372      * @see #evenClass
373      */

374     public void setEvenClass(String JavaDoc evenClass) {
375         this.evenClass = evenClass;
376     }
377
378     /**
379      * Returns whether first row is even
380      *
381      * @return whether first row is even
382      * @see #firstRowEven
383      * @jsp.attribute required="false"
384      * rtexprvalue="true"
385      * type="java.lang.Boolean"
386      * description="Indicates which CSS class to use for first row"
387      */

388     public Boolean JavaDoc getFirstRowEven() {
389         return firstRowEven;
390     }
391
392     /**
393      * Sets whether first row is even
394      *
395      * @param firstRowEven whether first row is even
396      * @see #firstRowEven
397      */

398     public void setFirstRowEven(Boolean JavaDoc firstRowEven) {
399         this.firstRowEven = firstRowEven;
400     }
401
402     /**
403      * Returns name of variable that will accept CSS style for current row
404      *
405      * @return CSS variable name
406      * @see #cssVar
407      * @jsp.attribute required="false"
408      * rtexprvalue="false"
409      * type="java.lang.String"
410      * description="Name of page scope variable to save CSS class under"
411      */

412     public String JavaDoc getCssVar() {
413         return cssVar;
414     }
415
416     /**
417      * Sets name of variable that will accept CSS style for current row
418      *
419      * @param cssVar CSS variable name to set
420      * @see #cssVar
421      */

422     public void setCssVar(String JavaDoc cssVar) {
423         this.cssVar = cssVar;
424     }
425
426     /**
427      * Returns name of variable that will accept index of current iteration
428      *
429      * @return index variable name
430      * @see #indexId
431      * @jsp.attribute required="false"
432      * rtexprvalue="true"
433      * type="java.lang.String"
434      * description="If specified, index of each iteration will be saved in corresponding page context"
435      */

436     public String JavaDoc getIndexId() {
437         return indexId;
438     }
439
440     /**
441      * Sets name of variable that will accept index of current iteration
442      *
443      * @param indexId index variable name to set
444      * @see #indexId
445      */

446     public void setIndexId(String JavaDoc indexId) {
447         this.indexId = indexId;
448     }
449
450     /**
451      * Constructs an iterator for collection of rows and loops through the body once per element.
452      *
453      * @throws JspTagException if a JSP exception has occurred
454      * @throws IOException if there is an error when invoking body content
455      */

456     public void doTag() throws JspException JavaDoc, IOException JavaDoc {
457
458         PageContext JavaDoc pageContext = (PageContext JavaDoc) getJspContext();
459
460         GridTag parentGridTag = (GridTag) findAncestorWithClass(this, GridTag.class);
461
462         if ( parentGridTag == null ) {
463             JspTagException JavaDoc e = new JspTagException JavaDoc("Parent tag is invalid! This tag is only valid when nested within 'grid' tag");
464             throw e;
465         }
466
467         // check beanId, method and collection attributes
468
if ( (beanId == null || method == null) && collection == null ) {
469             // error - either collection or beanId with method attributes must be specified
470
String JavaDoc errorMessage = "Either collection or beanId with method attributes must be specified";
471             JspTagException JavaDoc e = new JspTagException JavaDoc(errorMessage);
472             throw e;
473         }
474
475         // Get parameters from parent Grid tag
476
Integer JavaDoc pageSize = parentGridTag.getPageSize();
477
478         Grid grid = parentGridTag.getGrid();
479
480         if ( cssVar == null && ((oddClass != null && oddClass.trim().length() != 0) || (evenClass != null && evenClass.trim().length() != 0)) ) {
481             cssVar = TaglibConstants.ROW_CLASS_ATTR;
482         }
483
484         if ( indexId == null ) {
485             indexId = TaglibConstants.INDEX_ID_ATTR;
486         }
487
488         Integer JavaDoc pageNumber = parentGridTag.getCurrentPageNumber();
489
490         // check, if there are empty rows
491
int gridTotal = parentGridTag.getGrid().getTotal().intValue();
492         int pn = pageNumber.intValue();
493         int ps = pageSize.intValue();
494
495         // number of already displayed elements
496
int displayedCount = ps * (pn - 1);
497
498         Integer JavaDoc offset = new Integer JavaDoc(displayedCount > gridTotal ? displayedCount - gridTotal : 0);
499         Integer JavaDoc limit = new Integer JavaDoc(displayedCount > gridTotal ? ps : displayedCount + ps - gridTotal);
500
501         if ( limit.intValue() < 0 ) {
502             limit = new Integer JavaDoc(0);
503         }
504
505         if ( beanId == null || method == null ) {
506             Collection c = null;
507             // collection attribute is specified.
508
if ( collection instanceof Collection ) {
509                 c = (Collection) collection;
510             } else if ( collection instanceof Object JavaDoc[] ) {
511                 c = Arrays.asList((Object JavaDoc[]) collection);
512             } else if ( collection instanceof Map ) {
513                 c = ((Map) collection).entrySet();
514             } else {
515                 JspTagException JavaDoc e = new JspTagException JavaDoc("Only instances of java.util.Collection, java.lang.Object[] and java.util.Map are supported in collection attribute of RowsIteratorTag");
516                 throw e;
517             }
518
519             // sort collection
520
if ( !grid.getSortFields().isEmpty() ) {
521                 SortField sortField = grid.getSortFieldByIndex(0, tagId);
522                 if ( sortField != null ) {
523                     String JavaDoc property = sortField.getProperty();
524                     EntityFieldComparator comparator = new EntityFieldComparator(property);
525                     if ( !sortField.isOrderAscending() ) {
526                         comparator.reverseOrder();
527                     }
528                     if ( !(collection instanceof Map) ) {
529                         List list = new ArrayList(c);
530                         Collections.sort(list, comparator);
531                         c = list;
532                     } else {
533                         SortedMap sortedMap = new TreeMap(comparator);
534                         sortedMap.putAll((Map) collection);
535                         c = new LinkedHashSet(sortedMap.entrySet());
536                     }
537                 }
538             }
539
540             List subList = new ArrayList();
541
542             if ( c instanceof PartialCollection ) {
543                 PartialCollection partialCollection = (PartialCollection) c;
544                 grid.addTotal(partialCollection.getTotal());
545                 subList = partialCollection.asList();
546             } else {
547                 grid.addTotal(c.size());
548                 List list = new LinkedList(c);
549
550                 if ( gridTotal + list.size() <= displayedCount ) {
551                     subList = new ArrayList();
552                 } else {
553                     int fromIndex = offset.intValue();
554                     int toIndex = offset.intValue() + limit.intValue() < list.size() ? offset.intValue() + limit.intValue() : list.size();
555
556                     if ( fromIndex < list.size() ) {
557                         subList = list.subList(fromIndex, toIndex);
558                     }
559                 }
560             }
561             rowsIterator = subList.iterator();
562
563         } else {
564
565             PartialCollection rows = new PartialCollection();
566
567             // Find Spring bean in application context and find specified method on this bean
568

569             if ( applicationCtx == null ) {
570                 applicationCtx = WebApplicationContextUtils.getRequiredWebApplicationContext(pageContext.getServletContext());
571             }
572
573             Object JavaDoc bean = applicationCtx.getBean(beanId);
574             if ( bean == null ) {
575                 String JavaDoc errorMessage = "No bean with ID=" + beanId + " could be found in application context";
576                 if ( log.isErrorEnabled() ) {
577                     log.error(errorMessage);
578                 }
579                 JspTagException JavaDoc e = new JspTagException JavaDoc(errorMessage);
580                 throw e;
581             }
582             if ( log.isDebugEnabled() ) {
583                 log.debug("Bean with ID=" + beanId + " has been succefully found in application context");
584             }
585
586             Method JavaDoc method = null;
587             try {
588                 method = bean.getClass().getMethod(this.method, new Class JavaDoc[]{QueryInfo.class});
589             } catch ( NoSuchMethodException JavaDoc e ) {
590                 if ( log.isErrorEnabled() ) {
591                     log.error(e.getMessage());
592                 }
593                 throw new JspTagException JavaDoc(e);
594             }
595
596             if ( log.isDebugEnabled() ) {
597                 log.debug("Method '" + this.method + "' was found on bean with ID=" + beanId);
598             }
599
600
601             // Invoke method in bean and get collection of elements to display. Eval body then
602

603             try {
604
605                 String JavaDoc whereClause = grid.getWhereClause(tagId);
606                 String JavaDoc orderByClause = grid.getOrderByClause(tagId);
607                 QueryInfo queryInfo = new QueryInfo(whereClause, orderByClause, limit, offset);
608                 queryInfo.setQueryParameters(grid.getQueryParameters());
609                 rows = (PartialCollection) method.invoke(bean, new Object JavaDoc[]{queryInfo});
610
611                 parentGridTag.getGrid().addTotal(rows.getTotal().intValue());
612
613                 // TODO: pay attention to this part of code
614
// if ( gridTotal + rows.size() <= displayedCount ) {
615
// rows = new PartialCollection();
616
// }
617

618             } catch ( Exception JavaDoc e ) {
619                 throw new JspTagException JavaDoc(e);
620             }
621             rowsIterator = rows.iterator();
622         }
623
624         if ( firstRowEven == null ) {
625             firstRowEven = Boolean.TRUE;
626         }
627
628         if ( pageContext.getAttribute(IS_ODD_ROW_KEY) != null ) {
629             isOddRow = ((Boolean JavaDoc) pageContext.getAttribute(IS_ODD_ROW_KEY)).booleanValue();
630         } else {
631             // determine evennes
632
isOddRow = !firstRowEven.booleanValue();
633         }
634
635         while ( rowsIterator.hasNext() ) {
636             // export next element to page context
637
Object JavaDoc element = rowsIterator.next();
638             if ( element == null ) {
639                 pageContext.removeAttribute(var);
640             } else {
641                 pageContext.setAttribute(var, element);
642             }
643
644             if ( cssVar != null ) {
645                 String JavaDoc rowClass = isOddRow ? oddClass : evenClass;
646                 isOddRow = !isOddRow;
647                 pageContext.setAttribute(cssVar, rowClass);
648             }
649
650             pageContext.setAttribute(indexId, new Integer JavaDoc(loopCount++));
651
652             // invoke body to standard output
653
JspFragment JavaDoc body = getJspBody();
654             if ( body != null ) {
655                 body.invoke(null);
656             }
657         }
658
659         if ( loopCount > 0 ) {
660             // save isOddRow variable value for another iterators, if they exist
661
pageContext.setAttribute(IS_ODD_ROW_KEY, Boolean.valueOf(isOddRow));
662         }
663
664     }
665 }
666
Popular Tags