Source Code Cross Referenced for LoopTagSupport.java in  » Content-Management-System » apache-lenya-2.0 » org » apache » cocoon » taglib » core » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Content Management System » apache lenya 2.0 » org.apache.cocoon.taglib.core 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Licensed to the Apache Software Foundation (ASF) under one or more
003:         * contributor license agreements.  See the NOTICE file distributed with
004:         * this work for additional information regarding copyright ownership.
005:         * The ASF licenses this file to You under the Apache License, Version 2.0
006:         * (the "License"); you may not use this file except in compliance with
007:         * the License.  You may obtain a copy of the License at
008:         * 
009:         *      http://www.apache.org/licenses/LICENSE-2.0
010:         * 
011:         * Unless required by applicable law or agreed to in writing, software
012:         * distributed under the License is distributed on an "AS IS" BASIS,
013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014:         * See the License for the specific language governing permissions and
015:         * limitations under the License.
016:         */
017:
018:        package org.apache.cocoon.taglib.core;
019:
020:        import org.apache.cocoon.environment.ObjectModelHelper;
021:        import org.apache.cocoon.environment.Request;
022:        import org.apache.cocoon.taglib.IterationTag;
023:        import org.apache.cocoon.taglib.VarTagSupport;
024:        import org.xml.sax.Attributes;
025:        import org.xml.sax.SAXException;
026:
027:        /**
028:         * <p>Cocoon taglib allows developers to write custom iteration tags by
029:         * implementing the LoopTag interface.  (This is not to be confused with
030:         * org.apache.cocoon.taglib.IterationTag) 
031:         * LoopTag establishes a mechanism for iteration tags to be recognized
032:         * and for type-safe communication with custom subtags.
033:         * </p>
034:         * 
035:         * <p>Since most iteration tags will behave identically with respect to
036:         * actual iterative behavior, however, Cocoon taglib provides this
037:         * base support class to facilitate implementation.  Many iteration tags
038:         * will extend this and merely implement the hasNext() and next() methods
039:         * to provide contents for the handler to iterate over.</p>
040:         *
041:         * <p>In particular, this base class provides support for:</p>
042:         * 
043:         * <ul>
044:         *  <li> iteration control, based on protected next() and hasNext() methods
045:         *  <li> subsetting (begin, end, step functionality, including validation
046:         *       of subset parameters for sensibility)
047:         *  <li> item retrieval (getCurrent())
048:         *  <li> status retrieval (LoopTagStatus)
049:         *  <li> exposing attributes (set by 'var' and 'varStatus' attributes)
050:         * </ul>
051:         *
052:         * <p>In providing support for these tasks, LoopTagSupport contains
053:         * certain control variables that act to modify the iteration.  Accessors
054:         * are provided for these control variables when the variables represent
055:         * information needed or wanted at translation time (e.g., var, status).  For
056:         * other variables, accessors cannot be provided here since subclasses
057:         * may differ on their implementations of how those accessors are received.
058:         * For instance, one subclass might accept a String and convert it into
059:         * an object of a specific type by using an expression evaluator; others
060:         * might accept objects directly.  Still others might not want to expose
061:         * such information to outside control.</p>
062:         * 
063:         * Migration from JSTL1.0
064:         * @see javax.servlet.jsp.jstl.core.LoopTagSupport
065:         *
066:         * @author <a href="mailto:volker.schmitt@basf-it-services.com">Volker Schmitt</a>
067:         * @version CVS $Id: LoopTagSupport.java 433543 2006-08-22 06:22:54Z crossley $
068:         */
069:        public abstract class LoopTagSupport extends VarTagSupport implements 
070:                LoopTag, IterationTag //, TryCatchFinally
071:        {
072:            //*********************************************************************
073:            // 'Protected' state 
074:
075:            /*
076:             * JavaBean-style properties and other state slaved to them.  These
077:             * properties can be set directly by accessors; they will not be
078:             * modified by the LoopTagSupport implementation -- and should
079:             * not be modified by subclasses outside accessors unless those
080:             * subclasses are perfectly aware of what they're doing.
081:             * (An example where such non-accessor modification might be sensible
082:             * is in the doStartTag() method of an EL-aware subclass.)
083:             */
084:
085:            /** Starting index ('begin' attribute) */
086:            protected int begin;
087:
088:            /**
089:             * Ending index ('end' attribute).  -1 internally indicates 'no end
090:             * specified', although accessors for the core JSTL tags do not
091:             * allow this value to be supplied directly by the user.
092:             */
093:            protected int end;
094:
095:            /** Iteration step ('step' attribute) */
096:            protected int step;
097:
098:            /** Boolean flag indicating whether 'begin' was specified. */
099:            protected boolean beginSpecified;
100:
101:            /** Boolean flag indicating whether 'end' was specified. */
102:            protected boolean endSpecified;
103:
104:            /** Boolean flag indicating whether 'step' was specified. */
105:            protected boolean stepSpecified;
106:
107:            /** Attribute-exposing control */
108:            protected String statusId;
109:
110:            //*********************************************************************
111:            // 'Private' state (implementation details)
112:
113:            /*
114:             * State exclusively internal to the default, reference implementation.
115:             * (While this state is kept private to ensure consistency, 'status'
116:             * and 'item' happen to have one-for-one, read-only, accesor methods
117:             * as part of the LoopTag interface.)
118:             *
119:             * 'last' is kept separately for two reasons:  (a) to avoid
120:             * running a computation every time it's requested, and (b) to
121:             * let LoopTagStatus.isLast() avoid throwing any exceptions,
122:             * which would complicate subtag and scripting-variable use.
123:             *
124:             * Our 'internal index' begins at 0 and increases by 'step' each
125:             * round; this is arbitrary, but it seemed a simple way of keeping
126:             * track of the information we need.  To avoid computing
127:             * getIteratorStatus().getCount() by dividing index / step, we keep
128:             * a separate 'count' and increment it by 1 each round (as a minor
129:             * performance improvement).
130:             */
131:            private LoopTagStatus status; // our LoopTagStatus
132:            private Object item; // the current item
133:            protected int index; // the current internal index
134:            protected int count; // the iteration count
135:            protected boolean last; // current round == last one?
136:
137:            //*********************************************************************
138:            // Constructor
139:
140:            /**
141:             * Constructs a new LoopTagSupport.  As with TagSupport, subclasses
142:             * should not provide other constructors and are expected to call
143:             * the superclass constructor
144:             */
145:            public LoopTagSupport() {
146:                super ();
147:                init();
148:            }
149:
150:            //*********************************************************************
151:            // Abstract methods
152:
153:            /**
154:             * <p>Returns the next object over which the tag should iterate.  This
155:             * method must be provided by concrete subclasses of LoopTagSupport
156:             * to inform the base logic about what objects it should iterate over.</p>
157:             *
158:             * <p>It is expected that this method will generally be backed by an
159:             * Iterator, but this will not always be the case.  In particular, if
160:             * retrieving the next object raises the possibility of an exception
161:             * being thrown, this method allows that exception to propagate back
162:             * to the container as a SAXException; a standalone Iterator
163:             * would not be able to do this.  (This explains why LoopTagSupport
164:             * does not simply call for an Iterator from its subtags.)</p>
165:             * 
166:             * @return the java.lang.Object to use in the next round of iteration
167:             * @exception org.xml.sax.SAXException
168:             *            for other, unexpected exceptions
169:             */
170:            protected abstract Object next() throws SAXException;
171:
172:            /**
173:             * <p>Returns information concerning the availability of more items
174:             * over which to iterate.  This method must be provided by concrete
175:             * subclasses of LoopTagSupport to assist the iterative logic
176:             * provided by the supporting base class.</p>
177:             *  
178:             * <p>See <a href="#next()">next</a> for more information about the
179:             * purpose and expectations behind this tag.</p>
180:             *
181:             * @return <tt>true</tt> if there is at least one more item to iterate
182:             *         over, <tt>false</tt> otherwise
183:             * @exception org.xml.sax.SAXException
184:             * @see #next()
185:             */
186:            protected abstract boolean hasNext() throws SAXException;
187:
188:            /**
189:             * <p>Prepares for a single tag invocation.  Specifically, allows
190:             * subclasses to prepare for calls to hasNext() and next(). 
191:             * Subclasses can assume that prepare() will be called once for
192:             * each invocation of doStartTag() in the superclass.</p>
193:             *
194:             * @exception org.xml.sax.SAXException
195:             */
196:            protected abstract void prepare() throws SAXException;
197:
198:            //*********************************************************************
199:            // Lifecycle management and implementation of iterative behavior
200:
201:            // Releases any resources we may have (or inherit)
202:            public void recycle() {
203:                unExposeVariables(); // XXX if doFinally is supported this can removed
204:                init();
205:                super .recycle();
206:            }
207:
208:            // Begins iterating by processing the first item.
209:            public int doStartTag(String namespaceURI, String localName,
210:                    String qName, Attributes atts) throws SAXException {
211:
212:                // make sure 'begin' isn't greater than 'end'
213:                if (end != -1 && begin > end)
214:                    throw new SAXException("begin (" + begin + ") > end ("
215:                            + end + ")");
216:
217:                // we're beginning a new iteration, so reset our counts (etc.)
218:                index = 0;
219:                count = 1;
220:                last = false;
221:
222:                // let the subclass conduct any necessary preparation
223:                prepare();
224:
225:                // throw away the first 'begin' items (if they exist)
226:                discardIgnoreSubset(begin);
227:
228:                // get the item we're interested in
229:                if (hasNext())
230:                    // index is 0-based, so we don't update it for the first item
231:                    item = next();
232:                else
233:                    return SKIP_BODY;
234:
235:                /*
236:                 * now discard anything we have to "step" over.
237:                 * (we do this in advance to support LoopTagStatus.isLast())
238:                 */
239:                discard(step - 1);
240:
241:                // prepare to include our body...
242:                exposeVariables();
243:                calibrateLast();
244:                return EVAL_BODY;
245:            }
246:
247:            /*
248:             * Continues the iteration when appropriate -- that is, if we (a) have
249:             * more items and (b) don't run over our 'end' (given our 'step').
250:             */
251:            public int doAfterBody() throws SAXException {
252:
253:                // re-sync the index, given our prior behind-the-scenes 'step'
254:                index += step - 1;
255:
256:                // increment the count by 1 for each round
257:                count++;
258:
259:                // everything's been prepared for us, so just get the next item
260:                if (hasNext() && !atEnd()) {
261:                    index++;
262:                    item = next();
263:                } else
264:                    return SKIP_BODY;
265:
266:                /*
267:                 * now discard anything we have to "step" over.
268:                 * (we do this in advance to support LoopTagStatus.isLast())
269:                 */
270:                discard(step - 1);
271:
272:                // prepare to re-iterate...
273:                exposeVariables();
274:                calibrateLast();
275:                return EVAL_BODY_AGAIN;
276:            }
277:
278:            /*
279:             * Removes attributes that our tag set; these attributes are intended
280:             * to support scripting variables with NESTED scope, so we don't want
281:             * to pollute attribute space by leaving them lying around.
282:             */
283:            public void doFinally() {
284:                /*
285:                 * Make sure to un-expose variables, restoring them to their
286:                 * prior values, if applicable.
287:                 */
288:                unExposeVariables();
289:            }
290:
291:            /*
292:             * Be transparent with respect to exceptions: rethrow anything we get.
293:             */
294:            public void doCatch(Throwable t) throws Throwable {
295:                throw t;
296:            }
297:
298:            //*********************************************************************
299:            // Accessor methods
300:
301:            /*
302:             * Overview:  The getXXX() methods we provide implement the Tag
303:             * contract.  setXXX() accessors are provided only for those
304:             * properties (attributes) that must be known at translation time,
305:             * on the premise that these accessors will vary less than the
306:             * others in terms of their interface with the page author.
307:             */
308:
309:            /*
310:             * (Purposely inherit JavaDoc and semantics from LoopTag.
311:             * Subclasses can override this if necessary, but such a need is
312:             * expected to be rare.)
313:             */
314:            public Object getCurrent() {
315:                return item;
316:            }
317:
318:            /*
319:             * (Purposely inherit JavaDoc and semantics from LoopTag.
320:             * Subclasses can override this method for more fine-grained control
321:             * over LoopTagStatus, but an effort has been made to simplify
322:             * implementation of subclasses that are happy with reasonable default
323:             * behavior.)
324:             */
325:            public LoopTagStatus getIteratorStatus() {
326:
327:                // local implementation with reasonable default behavior
328:                class Status implements  LoopTagStatus {
329:
330:                    /*
331:                     * All our methods are straightforward.  We inherit
332:                     * our JavaDoc from LoopTagSupport; see that class
333:                     * for more information.
334:                     */
335:
336:                    public Object getCurrent() {
337:                        /*
338:                         * Access the item through getCurrent() instead of just
339:                         * returning the item our containing class stores.  This
340:                         * should allow a subclass of LoopTagSupport to override
341:                         * getCurrent() without having to rewrite getIteratorStatus() too.
342:                         */
343:                        return (LoopTagSupport.this .getCurrent());
344:                    }
345:
346:                    public int getIndex() {
347:                        return index + begin; // our 'index' isn't getIndex()
348:                    }
349:
350:                    public int getCount() {
351:                        return count;
352:                    }
353:
354:                    public boolean isFirst() {
355:                        return (index == 0); // our 'index' isn't getIndex()
356:                    }
357:
358:                    public boolean isLast() {
359:                        return (last); // use cached value
360:                    }
361:
362:                    public Integer getBegin() {
363:                        if (beginSpecified) {
364:                            return (new Integer(begin));
365:                        }
366:                        return null;
367:                    }
368:
369:                    public Integer getEnd() {
370:                        if (endSpecified) {
371:                            return (new Integer(end));
372:                        }
373:                        return null;
374:                    }
375:
376:                    public Integer getStep() {
377:                        if (stepSpecified) {
378:                            return (new Integer(step));
379:                        }
380:                        return null;
381:                    }
382:                }
383:
384:                /*
385:                 * We just need one per invocation...  Actually, for the current
386:                 * implementation, we just need one per instance, but I'd rather
387:                 * not keep the reference around once release() has been called.
388:                 */
389:                if (status == null) {
390:                    status = new Status();
391:                }
392:
393:                return status;
394:            }
395:
396:            /*
397:             * We only support setter methods for attributes that need to be
398:             * offered as Strings or other literals; other attributes will be
399:             * handled directly by implementing classes, since there might be
400:             * both rtexprvalue- and EL-based varieties, which will have
401:             * different signatures.  (We can't pollute child classes by having
402:             * base implementations of those setters here; child classes that
403:             * have attributes with different signatures would end up having
404:             * two incompatible setters, which is illegal for a JavaBean.
405:             */
406:
407:            // for tag attribute
408:            public void setVarStatus(String statusId) {
409:                this .statusId = statusId;
410:            }
411:
412:            //*********************************************************************
413:            // Protected utility methods
414:
415:            /* 
416:             * These methods validate attributes common to iteration tags.
417:             * Call them if your own subclassing implementation modifies them
418:             * -- e.g., if you set them through an expression language.
419:             */
420:
421:            /**
422:             * Ensures the "begin" property is sensible, throwing an exception
423:             * expected to propagate up if it isn't
424:             */
425:            protected void validateBegin() throws SAXException {
426:                if (begin < 0)
427:                    throw new SAXException("'begin' < 0");
428:            }
429:
430:            /**
431:             * Ensures the "end" property is sensible, throwing an exception
432:             * expected to propagate up if it isn't
433:             */
434:            protected void validateEnd() throws SAXException {
435:                if (end < 0)
436:                    throw new SAXException("'end' < 0");
437:            }
438:
439:            /**
440:             * Ensures the "step" property is sensible, throwing an exception
441:             * expected to propagate up if it isn't
442:             */
443:            protected void validateStep() throws SAXException {
444:                if (step < 1)
445:                    throw new SAXException("'step' <= 0");
446:            }
447:
448:            //*********************************************************************
449:            // Private utility methods
450:
451:            /** (Re)initializes state (during release() or construction) */
452:            private void init() {
453:                // defaults for internal bookkeeping
454:                index = 0; // internal index always starts at 0
455:                count = 1; // internal count always starts at 1
456:                status = null; // we clear status on release()
457:                item = null; // item will be retrieved for each round
458:                last = false; // last must be set explicitly
459:                beginSpecified = false; // not specified until it's specified :-)
460:                endSpecified = false; // (as above)
461:                stepSpecified = false; // (as above)
462:
463:                // defaults for interface with page author
464:                begin = 0; // when not specified, 'begin' is 0 by spec.
465:                end = -1; // when not specified, 'end' is not used
466:                step = 1; // when not specified, 'step' is 1
467:                statusId = null; // when not specified, no variable exported
468:            }
469:
470:            /** Sets 'last' appropriately. */
471:            private void calibrateLast() throws SAXException {
472:                /*
473:                 * the current round is the last one if (a) there are no remaining
474:                 * elements, or (b) the next one is beyond the 'end'.
475:                 */
476:                last = !hasNext() || atEnd()
477:                        || (end != -1 && (begin + index + step > end));
478:            }
479:
480:            /**
481:             * Exposes attributes (formerly scripting variables, but no longer!)
482:             * if appropriate.  Note that we don't really care, here, whether they're
483:             * scripting variables or not.
484:             */
485:            private void exposeVariables() throws SAXException {
486:
487:                /*
488:                 * We need to support null items returned from next(); we
489:                 * do this simply by passing such non-items through to the
490:                 * scoped variable as effectively 'null' (that is, by calling
491:                 * removeAttribute()).
492:                 *
493:                 * Also, just to be defensive, we handle the case of a null
494:                 * 'status' object as well.
495:                 *
496:                 * We call getCurrent() and getIteratorStatus() (instead of just using
497:                 * 'item' and 'status') to bridge to subclasses correctly.
498:                 * A subclass can override getCurrent() or getIteratorStatus() but still
499:                 * depend on our doStartTag() and doAfterBody(), which call this
500:                 * method (exposeVariables()), to expose 'item' and 'status'
501:                 * correctly.
502:                 */
503:
504:                if (var != null) {
505:                    if (getCurrent() == null)
506:                        removeVariable(var);
507:                    else
508:                        setVariable(var, getCurrent());
509:                }
510:                if (statusId != null) {
511:                    if (getIteratorStatus() == null)
512:                        removeVariable(statusId);
513:                    else
514:                        setVariable(statusId, getIteratorStatus());
515:                }
516:
517:            }
518:
519:            /**
520:             * Removes page attributes that we have exposed and, if applicable,
521:             * restores them to their prior values (and scopes).
522:             */
523:            private void unExposeVariables() {
524:                // "nested" variables are now simply removed
525:                Request request = ObjectModelHelper.getRequest(objectModel);
526:                if (var != null)
527:                    request.removeAttribute(var);
528:                if (statusId != null)
529:                    request.removeAttribute(statusId);
530:            }
531:
532:            /**
533:             * Cycles through and discards up to 'n' items from the iteration.
534:             * We only know "up to 'n'", not "exactly n," since we stop cycling
535:             * if hasNext() returns false or if we hit the 'end' of the iteration.
536:             * Note: this does not update the iteration index, since this method
537:             * is intended as a behind-the-scenes operation.  The index must be
538:             * updated separately.  (I don't really like this, but it's the simplest
539:             * way to support isLast() without storing two separate inconsistent
540:             * indices.  We need to (a) make sure hasNext() refers to the next
541:             * item we actually *want* and (b) make sure the index refers to the
542:             * item associated with the *current* round, not the next one.
543:             * C'est la vie.)
544:             */
545:            private void discard(int n) throws SAXException {
546:                /*
547:                 * copy index so we can restore it, but we need to update it
548:                 * as we work so that atEnd() works
549:                 */
550:                int oldIndex = index;
551:                while (n-- > 0 && !atEnd() && hasNext()) {
552:                    index++;
553:                    next();
554:                }
555:                index = oldIndex;
556:            }
557:
558:            /**
559:             * Discards items ignoring subsetting rules.  Useful for discarding
560:             * items from the beginning (i.e., to implement 'begin') where we
561:             * don't want factor in the 'begin' value already.
562:             */
563:            private void discardIgnoreSubset(int n) throws SAXException {
564:                while (n-- > 0 && hasNext())
565:                    next();
566:            }
567:
568:            /**
569:             * Returns true if the iteration has past the 'end' index (with
570:             * respect to subsetting), false otherwise.  ('end' must be set
571:             * for atEnd() to return true; if 'end' is not set, atEnd()
572:             * always returns false.)
573:             */
574:            private boolean atEnd() {
575:                return ((end != -1) && (begin + index >= end));
576:            }
577:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.