KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > components > flow > WebContinuation


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
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 org.apache.cocoon.components.flow;
17
18 import java.util.ArrayList JavaDoc;
19 import java.util.Collections JavaDoc;
20 import java.util.Enumeration JavaDoc;
21 import java.util.HashMap JavaDoc;
22 import java.util.List JavaDoc;
23 import java.util.Map JavaDoc;
24
25 import org.apache.avalon.framework.logger.AbstractLogEnabled;
26 import org.apache.commons.collections.iterators.IteratorEnumeration;
27 import org.apache.commons.lang.StringUtils;
28
29 /**
30  * Representation of continuations in a Web environment.
31  *
32  * <p>Because a user may click on the back button of the browser and
33  * restart a saved computation in a continuation, each
34  * <code>WebContinuation</code> becomes the parent of a subtree of
35  * continuations.
36  *
37  * <p>If there is no parent <code>WebContinuation</code>, the created
38  * continuation becomes the root of a tree of
39  * <code>WebContinuation</code>s.
40  *
41  * @author <a HREF="mailto:ovidiu@cup.hp.com">Ovidiu Predescu</a>
42  * @since March 19, 2002
43  * @version CVS $Id: WebContinuation.java 293102 2005-10-02 12:32:38Z reinhard $
44  */

45 public class WebContinuation extends AbstractLogEnabled
46                              implements Comparable JavaDoc {
47
48     /**
49      * The continuation this object represents.
50      */

51     protected Object JavaDoc continuation;
52
53     /**
54      * The parent <code>WebContinuation</code> from which processing
55      * last started. If null, there is no parent continuation
56      * associated, and this is the first one to be created in a
57      * processing. In this case this <code>WebContinuation</code>
58      * instance becomes the root of the tree maintained by the
59      * <code>ContinuationsManager</code>.
60      *
61      * @see ContinuationsManager
62      */

63     protected WebContinuation parentContinuation;
64
65     /**
66      * The children continuations. These are continuations created by
67      * resuming the processing from the point stored by
68      * <code>continuation</code>.
69      */

70     protected List JavaDoc children = new ArrayList JavaDoc();
71
72     /**
73      * The continuation id used to represent this instance in Web pages.
74      */

75     protected String JavaDoc id;
76     
77     /**
78      * Interpreter id that this continuation is bound to
79      */

80     protected String JavaDoc interpreterId;
81
82     /**
83      * A user definable object. This is present for convenience, to
84      * store any information associated with this
85      * <code>WebContinuation</code> a particular implementation might
86      * need.
87      */

88     protected Object JavaDoc userObject;
89
90     /**
91      * When was this continuation accessed last time. Each time the
92      * continuation is accessed, this time is set to the time of the
93      * access.
94      */

95     protected long lastAccessTime;
96
97     /**
98      * Indicates how long does this continuation will live (in
99      * seconds). The continuation will be removed once the current time
100      * is bigger than <code>lastAccessTime + timeToLive</code>.
101      */

102     protected int timeToLive;
103
104     /**
105      * Holds the <code>ContinuationsDisposer</code> to call when this continuation
106      * gets invalidated.
107      */

108     protected ContinuationsDisposer disposer;
109
110     /**
111      * The attributes of this continuation
112      */

113     private Map JavaDoc attributes;
114
115     /**
116      * Create a <code>WebContinuation</code> object. Saves the object in
117      * the hash table of continuations maintained by
118      * <code>manager</code> (this is done as a side effect of obtaining
119      * and identifier from it).
120      *
121      * @param continuation an <code>Object</code> value
122      * @param parentContinuation a <code>WebContinuation</code> value
123      * @param timeToLive time this continuation should live
124      * @param disposer a <code>ContinuationsDisposer</code> to call when this
125      * continuation gets invalidated.
126      */

127     WebContinuation(String JavaDoc id,
128                     Object JavaDoc continuation,
129                     WebContinuation parentContinuation,
130                     int timeToLive,
131                     String JavaDoc interpreterId,
132                     ContinuationsDisposer disposer) {
133         this.id = id;
134         this.continuation = continuation;
135         this.parentContinuation = parentContinuation;
136         this.updateLastAccessTime();
137         this.timeToLive = timeToLive;
138         this.interpreterId = interpreterId;
139         this.disposer = disposer;
140
141         if (parentContinuation != null) {
142             this.parentContinuation.children.add(this);
143         }
144     }
145
146     /**
147      * Get an attribute of this continuation
148      *
149      * @param name the attribute name.
150      */

151     public Object JavaDoc getAttribute(String JavaDoc name) {
152         if (this.attributes == null)
153             return null;
154         
155         return this.attributes.get(name);
156     }
157     
158     /**
159      * Set an attribute of this continuation
160      *
161      * @param name the attribute name
162      * @param value its value
163      */

164     public void setAttribute(String JavaDoc name, Object JavaDoc value) {
165         if (this.attributes == null) {
166             this.attributes = Collections.synchronizedMap(new HashMap JavaDoc());
167         }
168         
169         this.attributes.put(name, value);
170     }
171     
172     /**
173      * Remove an attribute of this continuation
174      *
175      * @param name the attribute name
176      */

177     public void removeAttribute(String JavaDoc name) {
178         if (this.attributes == null)
179             return;
180         
181         this.attributes.remove(name);
182     }
183     
184     /**
185      * Enumerate the attributes of this continuation.
186      *
187      * @return an enumeration of strings
188      */

189     public Enumeration JavaDoc getAttributeNames() {
190         if (this.attributes == null)
191             return new IteratorEnumeration();
192         
193         ArrayList JavaDoc keys = new ArrayList JavaDoc(this.attributes.keySet());
194         return new IteratorEnumeration(keys.iterator());
195     }
196
197     /**
198      * Return the continuation object.
199      *
200      * @return an <code>Object</code> value
201      */

202     public Object JavaDoc getContinuation() {
203         updateLastAccessTime();
204         return continuation;
205     }
206
207     /**
208      * Return the ancestor continuation situated <code>level</code>s
209      * above the current continuation. The current instance is
210      * considered to be at level 0. The parent continuation of the
211      * receiving instance at level 1, its parent is at level 2 relative
212      * to the receiving instance. If <code>level</code> is bigger than
213      * the depth of the tree, the root of the tree is returned.
214      *
215      * @param level an <code>int</code> value
216      * @return a <code>WebContinuation</code> value
217      */

218     public WebContinuation getContinuation(int level) {
219         if (level <= 0) {
220             updateLastAccessTime();
221             return this;
222         } else if (parentContinuation == null) {
223             return this;
224         } else {
225             return parentContinuation.getContinuation(level - 1);
226         }
227     }
228
229     /**
230      * Return the parent <code>WebContinuation</code>. Equivalent with
231      * <code>getContinuation(1)</code>.
232      *
233      * @return a <code>WebContinuation</code> value
234      */

235     public WebContinuation getParentContinuation() {
236         return parentContinuation;
237     }
238
239     /**
240      * Return the children <code>WebContinuation</code> which were
241      * created as a result of resuming the processing from the current
242      * <code>continuation</code>.
243      *
244      * @return a <code>List</code> value
245      */

246     public List JavaDoc getChildren() {
247         return children;
248     }
249
250     /**
251      * Returns the string identifier of this
252      * <code>WebContinuation</code>.
253      *
254      * @return a <code>String</code> value
255      */

256     public String JavaDoc getId() {
257         return id;
258     }
259
260     /**
261      * Returns the string identifier of the interpreter to which
262      * this <code>WebContinuation</code> is bound.
263      *
264      * @return a <code>String</code> value
265      */

266     public String JavaDoc getInterpreterId() {
267         return interpreterId;
268     }
269
270     /**
271      * Returns the last time this
272      * <code>WebContinuation</code> was accessed.
273      *
274      * @return a <code>long</code> value
275      */

276     public long getLastAccessTime() {
277         return lastAccessTime;
278     }
279
280     /**
281      * Returns the the timetolive for this
282      * <code>WebContinuation</code>.
283      *
284      * @return a <code>long</code> value
285      */

286     public long getTimeToLive() {
287         return this.timeToLive;
288     }
289
290     /**
291      * Sets the user object associated with this instance.
292      *
293      * @param obj an <code>Object</code> value
294      */

295     public void setUserObject(Object JavaDoc obj) {
296         this.userObject = obj;
297     }
298
299     /**
300      * Obtains the user object associated with this instance.
301      *
302      * @return an <code>Object</code> value
303      */

304     public Object JavaDoc getUserObject() {
305         return userObject;
306     }
307
308     /**
309      * Obtains the <code>ContinuationsDisposer</code> to call when this continuation
310      * is invalidated.
311      *
312      * @return a <code>ContinuationsDisposer</code> instance or null if there are
313      * no specific clean-up actions required.
314      */

315     ContinuationsDisposer getDisposer() {
316         return this.disposer;
317     }
318
319     /**
320      * Returns the hash code of the associated identifier.
321      *
322      * @return an <code>int</code> value
323      */

324     public int hashCode() {
325         return id.hashCode();
326     }
327
328     /**
329      * True if the identifiers are the same, false otherwise.
330      *
331      * @param another an <code>Object</code> value
332      * @return a <code>boolean</code> value
333      */

334     public boolean equals(Object JavaDoc another) {
335         if (another instanceof WebContinuation) {
336             return id.equals(((WebContinuation) another).id);
337         }
338         return false;
339     }
340
341     /**
342      * Compares the expiration time of this instance with that of the
343      * WebContinuation passed as argument.
344      *
345      * <p><b>Note:</b> this class has a natural ordering that is
346      * inconsistent with <code>equals</code>.</p>.
347      *
348      * @param other an <code>Object</code> value, which should be a
349      * <code>WebContinuation</code> instance
350      * @return an <code>int</code> value
351      */

352     public int compareTo(Object JavaDoc other) {
353         WebContinuation wk = (WebContinuation) other;
354         return (int) ((lastAccessTime + timeToLive)
355                 - (wk.lastAccessTime + wk.timeToLive));
356     }
357
358     /**
359      * Debugging method.
360      *
361      * <p>Assumes the receiving instance as the root of a tree and
362      * displays the tree of continuations.
363      */

364     public void display() {
365         getLogger().debug("\nWK: Tree" + display(0));
366     }
367
368     /**
369      * Debugging method.
370      *
371      * <p>Displays the receiving instance as if it is at the
372      * <code>indent</code> depth in the tree of continuations. Each
373      * level is indented 2 spaces.
374      *
375      * @param depth an <code>int</code> value
376      */

377     protected String JavaDoc display(int depth) {
378         StringBuffer JavaDoc tree = new StringBuffer JavaDoc("\n");
379         for (int i = 0; i < depth; i++) {
380             tree.append(" ");
381         }
382
383         tree.append("WK: WebContinuation ")
384                 .append(id)
385                 .append(" ExpireTime [");
386
387         if ((lastAccessTime + timeToLive) < System.currentTimeMillis()) {
388             tree.append("Expired");
389         } else {
390             tree.append(lastAccessTime + timeToLive);
391         }
392
393         tree.append("]");
394
395         // REVISIT: is this needed for some reason?
396
// System.out.print(spaces); System.out.println("WebContinuation " + id);
397

398         int size = children.size();
399         depth++;
400
401         for (int i = 0; i < size; i++) {
402             tree.append(((WebContinuation) children.get(i)).display(depth));
403         }
404
405         return tree.toString();
406     }
407
408     /**
409      * Update the continuation in the
410      */

411     protected void updateLastAccessTime() {
412         lastAccessTime = System.currentTimeMillis();
413     }
414
415     /**
416      * Determines whether this continuation has expired
417      *
418      * @return a <code>boolean</code> value
419      */

420     public boolean hasExpired() {
421         long currentTime = System.currentTimeMillis();
422         long expireTime = this.getLastAccessTime() + this.timeToLive;
423         
424         return (currentTime > expireTime);
425     }
426
427     /**
428      * Dispose this continuation. Should be called on invalidation.
429      */

430     public void dispose() {
431         // Call possible implementation-specific clean-up on this continuation.
432
if (this.disposer != null) {
433             this.disposer.disposeContinuation(this);
434         }
435         // Remove continuation object - will also serve as "disposed" flag
436
this.continuation = null;
437     }
438
439     /**
440      * Return true if this continuation was disposed of
441      */

442     public boolean disposed() {
443         return this.continuation == null;
444     }
445     
446     public boolean interpreterMatches( String JavaDoc interpreterId ) {
447         return StringUtils.equals( this.interpreterId, interpreterId );
448     }
449
450     public void detachFromParent() {
451         if (getParentContinuation() != null)
452             getParentContinuation().getChildren().remove(this);
453     }
454 }
455
Popular Tags