vgritsenko 2003/03/19 17:04:23
Modified: src/java/org/apache/cocoon/components/flow
ContinuationsManagerImpl.java WebContinuation.java
Log:
reformat code
Revision Changes Path
1.4 +273 -292
cocoon-2.1/src/java/org/apache/cocoon/components/flow/ContinuationsManagerImpl.java
Index: ContinuationsManagerImpl.java
===================================================================
RCS file:
/home/cvs/cocoon-2.1/src/java/org/apache/cocoon/components/flow/ContinuationsManagerImpl.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- ContinuationsManagerImpl.java 16 Mar 2003 17:49:11 -0000 1.3
+++ ContinuationsManagerImpl.java 20 Mar 2003 01:04:22 -0000 1.4
@@ -78,333 +78,314 @@
* @version CVS $Id$
*/
public class ContinuationsManagerImpl
- extends AbstractLogEnabled
- implements ContinuationsManager, Component, Configurable,
- ThreadSafe, Contextualizable {
-
- static final int CONTINUATION_ID_LENGTH = 20;
- static final String EXPIRE_CONTINUATIONS="expire-continuations";
-
-
- protected SecureRandom random = null;
- protected byte[] bytes;
-
- protected Sink m_commandSink;
-
- /**
- * How long does a continuation exist in memory since the last
- * access? The time is in miliseconds, and the default is 1 hour.
- */
- protected int defaultTimeToLive;
-
- /**
- * Maintains the forrest of <code>WebContinuation</code> trees.
- */
- protected Set forrest = Collections.synchronizedSet(new HashSet());
-
- /**
- * Association between <code>WebContinuation</code> ids and the
- * corresponding <code>WebContinuation</code> object.
- */
- protected Map idToWebCont = Collections.synchronizedMap(new HashMap());
-
- /**
- * Sorted set of <code>WebContinuation</code> instances, based on
- * their expiration time. This is used by the background thread to
- * invalidate continuations.
- */
- protected SortedSet expirations = Collections.synchronizedSortedSet(new
TreeSet());
-
- public ContinuationsManagerImpl()
- throws Exception
- {
- random = SecureRandom.getInstance("SHA1PRNG");
- random.setSeed(System.currentTimeMillis());
- bytes = new byte[CONTINUATION_ID_LENGTH];
- }
-
- public void configure(Configuration config)
- {
- defaultTimeToLive = config.getAttributeAsInteger("time-to-live", (3600 * 1000));
- Configuration expireConf = config.getChild("expirations-check");
-
- try {
- ContinuationInterrupt interrupt = new ContinuationInterrupt(expireConf);
- m_commandSink.enqueue(interrupt);
- }
- catch (Exception ex) {
- if (this.getLogger().isDebugEnabled()) {
- getLogger().debug("WK: Exception while configuring WKManager " + ex);
- }
- }
- }
-
- public WebContinuation createWebContinuation(Object kont,
- WebContinuation parentKont,
- int timeToLive)
- {
- int ttl = (timeToLive == 0 ? defaultTimeToLive : timeToLive);
-
- WebContinuation wk = new WebContinuation(kont, parentKont, this, ttl);
- wk.enableLogging(getLogger());
-
- if (parentKont == null)
- forrest.add(wk);
-
- // REVISIT: This Places only the "leaf" nodes in the expirations Sorted Set.
- // do we really want to do this?
- if (parentKont != null) {
- if (wk.getParentContinuation().getChildren().size() < 2) {
- expirations.remove(wk.getParentContinuation());
- }
- }
-
- expirations.add(wk);
-
- // No need to add the WebContinuation in idToWebCont as it was
- // already done during its construction.
-
- if (this.getLogger().isDebugEnabled()) {
- getLogger().debug("WK: Just Created New Continuation " + wk.getId());
- }
-
- return wk;
- }
-
- public void invalidateWebContinuation(WebContinuation wk)
- {
- WebContinuation parent = wk.getParentContinuation();
- if (parent == null)
- forrest.remove(wk);
- else {
- List parentKids = parent.getChildren();
- parentKids.remove(wk);
- }
-
- _invalidate(wk);
- }
-
- protected void _invalidate(WebContinuation wk)
- {
- if (this.getLogger().isDebugEnabled()) {
- getLogger().debug("WK: Manual Expire of Continuation " + wk.getId());
- }
- idToWebCont.remove(wk.getId());
- expirations.remove(wk);
-
- // Invalidate all the children continuations as well
- List children = wk.getChildren();
- int size = children.size();
- for (int i = 0; i < size; i++)
- _invalidate((WebContinuation)children.get(i));
- }
-
- public WebContinuation lookupWebContinuation(String id)
- {
- // REVISIT: Is the folliwing check needed to avoid threading issues:
- // return wk only if !(wk.hasExpired) ?
- return (WebContinuation)idToWebCont.get(id);
- }
-
- /**
- * Generate a unique identifier for a
- * <code>WebContinuation</code>. The identifier is generated using a
- * cryptographically strong algorithm to prevent people to generate
- * their own identifiers.
- *
- * <p>It has the side effect of interning the continuation object in
- * the <code>idToWebCont</code> hash table.
- *
- * @param wk a <code>WebContinuation</code> object for which the
- * identifier should be generated.
- * @return the <code>String</code> identifier of the
- * <code>WebContinuation</code>
- */
- public String generateContinuationId(WebContinuation wk)
- {
- char[] result = new char[bytes.length * 2];
- String continuationId = null;
-
- while (true) {
- random.nextBytes(bytes);
-
- for (int i = 0; i < CONTINUATION_ID_LENGTH; i++) {
- byte ch = bytes[i];
- result[2 * i] = Character.forDigit(Math.abs(ch >> 4), 16);
- result[2 * i + 1] = Character.forDigit(Math.abs(ch & 0x0f), 16);
- }
- continuationId = new String(result);
- synchronized(idToWebCont) {
- if (!idToWebCont.containsKey(continuationId)) {
- idToWebCont.put(continuationId, wk);
- break;
- }
- }
- }
-
- return continuationId;
- }
-
-
- /**
- * Removes an expired leaf <code>WebContinuation</code> node
- * from its continuation tree, and recursively removes its
- * parent(s) if it they have expired and have no (other) children.
- *
- * @param a <code>WebContinuation</code> node
- */
- public void removeContinuation(WebContinuation wk) {
- if (wk.getChildren().size() != 0) {
- return;
- }
-
- // remove access to this contination
- idToWebCont.remove(wk.getId());
-
- WebContinuation parent = wk.getParentContinuation();
- if (parent == null) {
- forrest.remove(wk);
- }
- else {
- List parentKids = parent.getChildren();
- parentKids.remove(wk);
- }
-
- if (this.getLogger().isDebugEnabled()) {
- getLogger().debug("WK: deleted this WK: " + wk.getId());
- }
-
- // now check if parent needs to be removed.
- if (null != parent && parent.hasExpired()) {
- removeContinuation(parent);
- }
- }
-
-
- /**
- * Dump to Log file the current contents of
- * the expirations <code>SortedSet</code>
- */
- public void displayExpireSet() {
- Iterator iter = expirations.iterator();
- StringBuffer wkSet = new StringBuffer("\nWK; Expire Set Size: "+
expirations.size());
- while (iter.hasNext()) {
- final WebContinuation wk = (WebContinuation)iter.next();
- final long lat = wk.getLastAccessTime() + wk.getTimeToLive();
- wkSet.append("\nWK: ")
- .append(wk.getId())
- .append(" ExpireTime [");
-
- if (lat < System.currentTimeMillis()) {
- wkSet.append("Expired");
- }
- else {
- wkSet.append(lat);
- }
- wkSet.append("]");
- }
-
- getLogger().debug(wkSet.toString());
- }
-
- /**
- * Dump to Log file all <code>WebContinuation</code>s
- * in the system
- */
- public void displayAllContinuations()
- {
- Iterator iter = forrest.iterator();
- while (iter.hasNext()) {
- ((WebContinuation)iter.next()).display();
- }
- }
-
- /**
- * Remove all continuations which have
- * already expired
- */
- public void expireContinuations() {
- // log state before continuations clean up
- if (this.getLogger().isDebugEnabled()) {
- getLogger().debug("WK: Forrest size: " + forrest.size());
- displayAllContinuations();
- displayExpireSet();
- }
-
- // clean up
- if (this.getLogger().isDebugEnabled()) {
- getLogger().debug("WK CurrentSytemTime[" + System.currentTimeMillis() +
- "]: Cleaning up expired Continuations....");
- }
- WebContinuation wk;
- Iterator iter = expirations.iterator();
- while (iter.hasNext() && ((wk=(WebContinuation)iter.next()).hasExpired())) {
- iter.remove();
- this.removeContinuation(wk);
- }
-
- // log state after continuations clean up
- if (this.getLogger().isDebugEnabled()) {
- getLogger().debug("WK: Forrest size: " + forrest.size());
- displayAllContinuations();
- displayExpireSet();
+ extends AbstractLogEnabled
+ implements ContinuationsManager, Component, Configurable,
+ ThreadSafe, Contextualizable {
+
+ static final int CONTINUATION_ID_LENGTH = 20;
+ static final String EXPIRE_CONTINUATIONS = "expire-continuations";
+
+ protected SecureRandom random = null;
+ protected byte[] bytes;
+
+ protected Sink m_commandSink;
+
+ /**
+ * How long does a continuation exist in memory since the last
+ * access? The time is in miliseconds, and the default is 1 hour.
+ */
+ protected int defaultTimeToLive;
+
+ /**
+ * Maintains the forrest of <code>WebContinuation</code> trees.
+ */
+ protected Set forrest = Collections.synchronizedSet(new HashSet());
+
+ /**
+ * Association between <code>WebContinuation</code> ids and the
+ * corresponding <code>WebContinuation</code> object.
+ */
+ protected Map idToWebCont = Collections.synchronizedMap(new HashMap());
+
+ /**
+ * Sorted set of <code>WebContinuation</code> instances, based on
+ * their expiration time. This is used by the background thread to
+ * invalidate continuations.
+ */
+ protected SortedSet expirations = Collections.synchronizedSortedSet(new
TreeSet());
+
+ public ContinuationsManagerImpl() throws Exception {
+ random = SecureRandom.getInstance("SHA1PRNG");
+ random.setSeed(System.currentTimeMillis());
+ bytes = new byte[CONTINUATION_ID_LENGTH];
+ }
+
+ public void configure(Configuration config) {
+ defaultTimeToLive = config.getAttributeAsInteger("time-to-live", (3600 *
1000));
+ Configuration expireConf = config.getChild("expirations-check");
+
+ try {
+ ContinuationInterrupt interrupt = new ContinuationInterrupt(expireConf);
+ m_commandSink.enqueue(interrupt);
+ } catch (Exception ex) {
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("WK: Exception while configuring WKManager " +
ex);
+ }
+ }
+ }
+
+ public WebContinuation createWebContinuation(Object kont,
+ WebContinuation parentKont,
+ int timeToLive) {
+ int ttl = (timeToLive == 0 ? defaultTimeToLive : timeToLive);
+
+ WebContinuation wk = new WebContinuation(kont, parentKont, this, ttl);
+ wk.enableLogging(getLogger());
+
+ if (parentKont == null) {
+ forrest.add(wk);
+ }
+
+ // REVISIT: This Places only the "leaf" nodes in the expirations Sorted Set.
+ // do we really want to do this?
+ if (parentKont != null) {
+ if (wk.getParentContinuation().getChildren().size() < 2) {
+ expirations.remove(wk.getParentContinuation());
+ }
+ }
+
+ expirations.add(wk);
+
+ // No need to add the WebContinuation in idToWebCont as it was
+ // already done during its construction.
+
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("WK: Just Created New Continuation " + wk.getId());
+ }
+
+ return wk;
+ }
+
+ public void invalidateWebContinuation(WebContinuation wk) {
+ WebContinuation parent = wk.getParentContinuation();
+ if (parent == null)
+ forrest.remove(wk);
+ else {
+ List parentKids = parent.getChildren();
+ parentKids.remove(wk);
+ }
+
+ _invalidate(wk);
+ }
+
+ protected void _invalidate(WebContinuation wk) {
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("WK: Manual Expire of Continuation " + wk.getId());
+ }
+ idToWebCont.remove(wk.getId());
+ expirations.remove(wk);
+
+ // Invalidate all the children continuations as well
+ List children = wk.getChildren();
+ int size = children.size();
+ for (int i = 0; i < size; i++)
+ _invalidate((WebContinuation) children.get(i));
+ }
+
+ public WebContinuation lookupWebContinuation(String id) {
+ // REVISIT: Is the folliwing check needed to avoid threading issues:
+ // return wk only if !(wk.hasExpired) ?
+ return (WebContinuation) idToWebCont.get(id);
+ }
+
+ /**
+ * Generate a unique identifier for a
+ * <code>WebContinuation</code>. The identifier is generated using a
+ * cryptographically strong algorithm to prevent people to generate
+ * their own identifiers.
+ *
+ * <p>It has the side effect of interning the continuation object in
+ * the <code>idToWebCont</code> hash table.
+ *
+ * @param wk a <code>WebContinuation</code> object for which the
+ * identifier should be generated.
+ * @return the <code>String</code> identifier of the
+ * <code>WebContinuation</code>
+ */
+ public String generateContinuationId(WebContinuation wk) {
+ char[] result = new char[bytes.length * 2];
+ String continuationId = null;
+
+ while (true) {
+ random.nextBytes(bytes);
+
+ for (int i = 0; i < CONTINUATION_ID_LENGTH; i++) {
+ byte ch = bytes[i];
+ result[2 * i] = Character.forDigit(Math.abs(ch >> 4), 16);
+ result[2 * i + 1] = Character.forDigit(Math.abs(ch & 0x0f), 16);
+ }
+ continuationId = new String(result);
+ synchronized (idToWebCont) {
+ if (!idToWebCont.containsKey(continuationId)) {
+ idToWebCont.put(continuationId, wk);
+ break;
+ }
+ }
+ }
+
+ return continuationId;
+ }
+
+
+ /**
+ * Removes an expired leaf <code>WebContinuation</code> node
+ * from its continuation tree, and recursively removes its
+ * parent(s) if it they have expired and have no (other) children.
+ *
+ * @param wk <code>WebContinuation</code> node
+ */
+ public void removeContinuation(WebContinuation wk) {
+ if (wk.getChildren().size() != 0) {
+ return;
+ }
+
+ // remove access to this contination
+ idToWebCont.remove(wk.getId());
+
+ WebContinuation parent = wk.getParentContinuation();
+ if (parent == null) {
+ forrest.remove(wk);
+ } else {
+ List parentKids = parent.getChildren();
+ parentKids.remove(wk);
+ }
+
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("WK: deleted this WK: " + wk.getId());
+ }
+
+ // now check if parent needs to be removed.
+ if (null != parent && parent.hasExpired()) {
+ removeContinuation(parent);
+ }
+ }
+
+
+ /**
+ * Dump to Log file the current contents of
+ * the expirations <code>SortedSet</code>
+ */
+ public void displayExpireSet() {
+ Iterator iter = expirations.iterator();
+ StringBuffer wkSet = new StringBuffer("\nWK; Expire Set Size: " +
expirations.size());
+ while (iter.hasNext()) {
+ final WebContinuation wk = (WebContinuation) iter.next();
+ final long lat = wk.getLastAccessTime() + wk.getTimeToLive();
+ wkSet.append("\nWK: ")
+ .append(wk.getId())
+ .append(" ExpireTime [");
+
+ if (lat < System.currentTimeMillis()) {
+ wkSet.append("Expired");
+ } else {
+ wkSet.append(lat);
+ }
+ wkSet.append("]");
+ }
+
+ getLogger().debug(wkSet.toString());
+ }
+
+ /**
+ * Dump to Log file all <code>WebContinuation</code>s
+ * in the system
+ */
+ public void displayAllContinuations() {
+ Iterator iter = forrest.iterator();
+ while (iter.hasNext()) {
+ ((WebContinuation) iter.next()).display();
+ }
+ }
+
+ /**
+ * Remove all continuations which have
+ * already expired
+ */
+ public void expireContinuations() {
+ // log state before continuations clean up
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("WK: Forrest size: " + forrest.size());
+ displayAllContinuations();
+ displayExpireSet();
+ }
+
+ // clean up
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("WK CurrentSytemTime[" + System.currentTimeMillis() +
+ "]: Cleaning up expired Continuations....");
+ }
+ WebContinuation wk;
+ Iterator iter = expirations.iterator();
+ while (iter.hasNext() && ((wk = (WebContinuation)
iter.next()).hasExpired())) {
+ iter.remove();
+ this.removeContinuation(wk);
+ }
+
+ // log state after continuations clean up
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("WK: Forrest size: " + forrest.size());
+ displayAllContinuations();
+ displayExpireSet();
+ }
}
- }
/**
* Get the command sink so that we can be notified of changes
*/
- public void contextualize(Context context) throws ContextException
- {
- m_commandSink = (Sink)context.get(Queue.ROLE);
- }
-
- public final class ContinuationInterrupt implements RepeatedCommand
- {
+ public void contextualize(Context context) throws ContextException {
+ m_commandSink = (Sink) context.get(Queue.ROLE);
+ }
+
+ public final class ContinuationInterrupt implements RepeatedCommand {
private final long m_interval;
private final long m_initialDelay;
-
+
/**
* @param expireConf
*/
- public ContinuationInterrupt(Configuration expireConf)
- {
+ public ContinuationInterrupt(Configuration expireConf) {
// only periodic time triggers are supported
m_initialDelay =
- expireConf.getChild( "offset", true ).getValueAsLong( 100 );
+ expireConf.getChild("offset", true).getValueAsLong(100);
m_interval =
- expireConf.getChild( "period", true ).getValueAsLong( 100 );
+ expireConf.getChild("period", true).getValueAsLong(100);
}
/**
* Repeat forever
*/
- public int getNumberOfRepeats()
- {
+ public int getNumberOfRepeats() {
return -1;
}
/**
* Get the number of millis to wait between invocations
*/
- public long getRepeatInterval()
- {
+ public long getRepeatInterval() {
return m_interval;
}
/**
* Get the number of millis to wait for the first invocation
*/
- public long getDelayInterval()
- {
+ public long getDelayInterval() {
return m_initialDelay;
}
/**
* expire any continuations that need expiring.
*/
- public void execute() throws Exception
- {
+ public void execute() throws Exception {
expireContinuations();
}
}
1.3 +282 -301
cocoon-2.1/src/java/org/apache/cocoon/components/flow/WebContinuation.java
Index: WebContinuation.java
===================================================================
RCS file:
/home/cvs/cocoon-2.1/src/java/org/apache/cocoon/components/flow/WebContinuation.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- WebContinuation.java 16 Mar 2003 17:49:11 -0000 1.2
+++ WebContinuation.java 20 Mar 2003 01:04:23 -0000 1.3
@@ -68,305 +68,286 @@
* @version CVS $Id$
*/
public class WebContinuation extends AbstractLogEnabled
- implements Comparable
-{
- /**
- * The continuation this object represents.
- */
- protected Object continuation;
-
- /**
- * The parent <code>WebContinuation</code> from which processing
- * last started. If null, there is no parent continuation
- * associated, and this is the first one to be created in a
- * processing. In this case this <code>WebContinuation</code>
- * instance becomes the root of the tree maintained by the
- * <code>ContinuationsManager</code>.
- *
- * @see ContinuationsManager
- */
- protected WebContinuation parentContinuation;
-
- /**
- * The children continuations. These are continuations created by
- * resuming the processing from the point stored by
- * <code>continuation</code>.
- */
- protected List children = new ArrayList();
-
- /**
- * The continuation id used to represent this instance in Web pages.
- */
- protected String id;
-
- /**
- * A user definable object. This is present for convenience, to
- * store any information associated with this
- * <code>WebContinuation</code> a particular implementation might
- * need.
- */
- protected Object userObject;
-
- /**
- * When was this continuation accessed last time. Each time the
- * continuation is accessed, this time is set to the time of the
- * access.
- */
- protected long lastAccessTime;
-
- /**
- * Indicates how long does this continuation will live (in
- * seconds). The continuation will be removed once the current time
- * is bigger than <code>lastAccessTime + timeToLive</code>.
- */
- protected int timeToLive;
-
- /**
- * Create a <code>WebContinuation</code> object. Saves the object in
- * the hash table of continuations maintained by
- * <code>manager</code> (this is done as a side effect of obtaining
- * and identifier from it).
- *
- * @param continuation an <code>Object</code> value
- * @param parentContinuation a <code>WebContinuation</code> value
- * @param manager a <code>ContinuationsManagerImpl</code> value
- */
- public WebContinuation(Object continuation,
- WebContinuation parentContinuation,
- ContinuationsManagerImpl manager,
- int timeToLive)
- {
- this.continuation = continuation;
- this.parentContinuation = parentContinuation;
- id = manager.generateContinuationId(this);
- this.updateLastAccessTime();
- this.timeToLive = timeToLive;
-
- if (parentContinuation != null)
- this.parentContinuation.children.add(this);
- }
-
- /**
- * Return the continuation object.
- *
- * @return an <code>Object</code> value
- */
- public Object getContinuation()
- {
- updateLastAccessTime();
- return continuation;
- }
-
- /**
- * Return the ancestor continuation situated <code>level</code>s
- * above the current continuation. The current instance is
- * considered to be at level 0. The parent continuation of the
- * receiving instance at level 1, its parent is at level 2 relative
- * to the receiving instance. If <code>level</code> is bigger than
- * the depth of the tree, the root of the tree is returned.
- *
- * @param level an <code>int</code> value
- * @return a <code>WebContinuation</code> value
- */
- public WebContinuation getContinuation(int level)
- {
- if (level <= 0) {
- updateLastAccessTime();
- return this;
- }
- else if (parentContinuation == null)
- return this;
- else
- return parentContinuation.getContinuation(level - 1);
- }
-
- /**
- * Return the parent <code>WebContinuation</code>. Equivalent with
- * <code>getContinuation(1)</code>.
- *
- * @return a <code>WebContinuation</code> value
- */
- public WebContinuation getParentContinuation()
- {
- return parentContinuation;
- }
-
- /**
- * Return the children <code>WebContinuation</code> which were
- * created as a result of resuming the processing from the current
- * <code>continuation</code>.
- *
- * @return a <code>List</code> value
- */
- public List getChildren()
- {
- return children;
- }
-
- /**
- * Returns the string identifier of this
- * <code>WebContinuation</code>.
- *
- * @return a <code>String</code> value
- */
- public String getId()
- {
- return id;
- }
-
- /**
- * Returns the last time this
- * <code>WebContinuation</code> was accessed.
- *
- * @return a <code>long</code> value
- */
- public long getLastAccessTime()
- {
- return lastAccessTime;
- }
-
- /**
- * Returns the the timetolive for this
- * <code>WebContinuation</code>.
- *
- * @return a <code>long</code> value
- */
- public long getTimeToLive()
- {
- return this.timeToLive;
- }
-
- /**
- * Sets the user object associated with this instance.
- *
- * @param obj an <code>Object</code> value
- */
- public void setUserObject(Object obj)
- {
- this.userObject = obj;
- }
-
- /**
- * Obtains the user object associated with this instance.
- *
- * @return an <code>Object</code> value
- */
- public Object getUserObject()
- {
- return userObject;
- }
-
- /**
- * Returns the hash code of the associated identifier.
- *
- * @return an <code>int</code> value
- */
- public int hashCode()
- {
- return id.hashCode();
- }
-
- /**
- * True if the identifiers are the same, false otherwise.
- *
- * @param another an <code>Object</code> value
- * @return a <code>boolean</code> value
- */
- public boolean equals(Object another)
- {
- if (another instanceof WebContinuation)
- return id.equals(((WebContinuation)another).id);
- return false;
- }
-
- /**
- * Compares the expiration time of this instance with that of the
- * WebContinuation passed as argument.
- *
- * <p><b>Note:</b> this class has a natural ordering that is
- * inconsistent with <code>equals</code>.</p>.
- *
- * @param other an <code>Object</code> value, which should be a
- * <code>WebContinuation</code> instance
- * @return an <code>int</code> value
- */
- public int compareTo(Object other)
- {
- WebContinuation wk = (WebContinuation)other;
- return (int)((lastAccessTime + timeToLive)
- - (wk.lastAccessTime + wk.timeToLive));
- }
-
- /**
- * Debugging method.
- *
- * <p>Assumes the receiving instance as the root of a tree and
- * displays the tree of continuations.
- */
- public void display()
- {
- getLogger().debug("\nWK: Tree" + display(0));
- }
-
- /**
- * Debugging method.
- *
- * <p>Displays the receiving instance as if it is at the
- * <code>indent</code> depth in the tree of continuations. Each
- * level is indented 2 spaces.
- *
- * @param depth an <code>int</code> value
- */
- protected String display(int depth)
- {
- StringBuffer tree = new StringBuffer("\n");
- for (int i = 0; i < depth; i++) {
- tree.append(" ");
- }
-
- tree.append("WK: WebContinuation ")
- .append(id)
- .append(" ExpireTime [");
-
- if ((lastAccessTime + timeToLive) < System.currentTimeMillis()) {
- tree.append("Expired");
- }
- else {
- tree.append(lastAccessTime + timeToLive);
- }
-
- tree.append("]");
-
- //REVISIT: is this needed for some reason?
- //System.out.print(spaces); System.out.println("WebContinuation " + id);
-
- int size = children.size();
- depth++;
-
- for (int i = 0; i < size; i++) {
- tree.append(((WebContinuation)children.get(i)).display(depth));
- }
-
- return tree.toString();
- }
-
- /**
- * Update the continuation in the
- */
- protected void updateLastAccessTime()
- {
- lastAccessTime = new Date().getTime();
- }
-
- /**
- * Determines whether this continuation has expired
- *
- * @return a <code>boolean</code> value
- */
- public boolean hasExpired() {
- long currentTime = System.currentTimeMillis();
- long expireTime = this.getLastAccessTime() + this.timeToLive;
+ implements Comparable {
+ /**
+ * The continuation this object represents.
+ */
+ protected Object continuation;
+
+ /**
+ * The parent <code>WebContinuation</code> from which processing
+ * last started. If null, there is no parent continuation
+ * associated, and this is the first one to be created in a
+ * processing. In this case this <code>WebContinuation</code>
+ * instance becomes the root of the tree maintained by the
+ * <code>ContinuationsManager</code>.
+ *
+ * @see ContinuationsManager
+ */
+ protected WebContinuation parentContinuation;
+
+ /**
+ * The children continuations. These are continuations created by
+ * resuming the processing from the point stored by
+ * <code>continuation</code>.
+ */
+ protected List children = new ArrayList();
+
+ /**
+ * The continuation id used to represent this instance in Web pages.
+ */
+ protected String id;
+
+ /**
+ * A user definable object. This is present for convenience, to
+ * store any information associated with this
+ * <code>WebContinuation</code> a particular implementation might
+ * need.
+ */
+ protected Object userObject;
+
+ /**
+ * When was this continuation accessed last time. Each time the
+ * continuation is accessed, this time is set to the time of the
+ * access.
+ */
+ protected long lastAccessTime;
+
+ /**
+ * Indicates how long does this continuation will live (in
+ * seconds). The continuation will be removed once the current time
+ * is bigger than <code>lastAccessTime + timeToLive</code>.
+ */
+ protected int timeToLive;
+
+ /**
+ * Create a <code>WebContinuation</code> object. Saves the object in
+ * the hash table of continuations maintained by
+ * <code>manager</code> (this is done as a side effect of obtaining
+ * and identifier from it).
+ *
+ * @param continuation an <code>Object</code> value
+ * @param parentContinuation a <code>WebContinuation</code> value
+ * @param manager a <code>ContinuationsManagerImpl</code> value
+ */
+ public WebContinuation(Object continuation,
+ WebContinuation parentContinuation,
+ ContinuationsManagerImpl manager,
+ int timeToLive) {
+ this.continuation = continuation;
+ this.parentContinuation = parentContinuation;
+ id = manager.generateContinuationId(this);
+ this.updateLastAccessTime();
+ this.timeToLive = timeToLive;
- return (currentTime > expireTime);
- }
+ if (parentContinuation != null)
+ this.parentContinuation.children.add(this);
+ }
+
+ /**
+ * Return the continuation object.
+ *
+ * @return an <code>Object</code> value
+ */
+ public Object getContinuation() {
+ updateLastAccessTime();
+ return continuation;
+ }
+
+ /**
+ * Return the ancestor continuation situated <code>level</code>s
+ * above the current continuation. The current instance is
+ * considered to be at level 0. The parent continuation of the
+ * receiving instance at level 1, its parent is at level 2 relative
+ * to the receiving instance. If <code>level</code> is bigger than
+ * the depth of the tree, the root of the tree is returned.
+ *
+ * @param level an <code>int</code> value
+ * @return a <code>WebContinuation</code> value
+ */
+ public WebContinuation getContinuation(int level) {
+ if (level <= 0) {
+ updateLastAccessTime();
+ return this;
+ } else if (parentContinuation == null)
+ return this;
+ else
+ return parentContinuation.getContinuation(level - 1);
+ }
+
+ /**
+ * Return the parent <code>WebContinuation</code>. Equivalent with
+ * <code>getContinuation(1)</code>.
+ *
+ * @return a <code>WebContinuation</code> value
+ */
+ public WebContinuation getParentContinuation() {
+ return parentContinuation;
+ }
+
+ /**
+ * Return the children <code>WebContinuation</code> which were
+ * created as a result of resuming the processing from the current
+ * <code>continuation</code>.
+ *
+ * @return a <code>List</code> value
+ */
+ public List getChildren() {
+ return children;
+ }
+
+ /**
+ * Returns the string identifier of this
+ * <code>WebContinuation</code>.
+ *
+ * @return a <code>String</code> value
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Returns the last time this
+ * <code>WebContinuation</code> was accessed.
+ *
+ * @return a <code>long</code> value
+ */
+ public long getLastAccessTime() {
+ return lastAccessTime;
+ }
+
+ /**
+ * Returns the the timetolive for this
+ * <code>WebContinuation</code>.
+ *
+ * @return a <code>long</code> value
+ */
+ public long getTimeToLive() {
+ return this.timeToLive;
+ }
+
+ /**
+ * Sets the user object associated with this instance.
+ *
+ * @param obj an <code>Object</code> value
+ */
+ public void setUserObject(Object obj) {
+ this.userObject = obj;
+ }
+
+ /**
+ * Obtains the user object associated with this instance.
+ *
+ * @return an <code>Object</code> value
+ */
+ public Object getUserObject() {
+ return userObject;
+ }
+
+ /**
+ * Returns the hash code of the associated identifier.
+ *
+ * @return an <code>int</code> value
+ */
+ public int hashCode() {
+ return id.hashCode();
+ }
+
+ /**
+ * True if the identifiers are the same, false otherwise.
+ *
+ * @param another an <code>Object</code> value
+ * @return a <code>boolean</code> value
+ */
+ public boolean equals(Object another) {
+ if (another instanceof WebContinuation)
+ return id.equals(((WebContinuation) another).id);
+ return false;
+ }
+
+ /**
+ * Compares the expiration time of this instance with that of the
+ * WebContinuation passed as argument.
+ *
+ * <p><b>Note:</b> this class has a natural ordering that is
+ * inconsistent with <code>equals</code>.</p>.
+ *
+ * @param other an <code>Object</code> value, which should be a
+ * <code>WebContinuation</code> instance
+ * @return an <code>int</code> value
+ */
+ public int compareTo(Object other) {
+ WebContinuation wk = (WebContinuation) other;
+ return (int) ((lastAccessTime + timeToLive)
+ - (wk.lastAccessTime + wk.timeToLive));
+ }
+
+ /**
+ * Debugging method.
+ *
+ * <p>Assumes the receiving instance as the root of a tree and
+ * displays the tree of continuations.
+ */
+ public void display() {
+ getLogger().debug("\nWK: Tree" + display(0));
+ }
+
+ /**
+ * Debugging method.
+ *
+ * <p>Displays the receiving instance as if it is at the
+ * <code>indent</code> depth in the tree of continuations. Each
+ * level is indented 2 spaces.
+ *
+ * @param depth an <code>int</code> value
+ */
+ protected String display(int depth) {
+ StringBuffer tree = new StringBuffer("\n");
+ for (int i = 0; i < depth; i++) {
+ tree.append(" ");
+ }
+
+ tree.append("WK: WebContinuation ")
+ .append(id)
+ .append(" ExpireTime [");
+
+ if ((lastAccessTime + timeToLive) < System.currentTimeMillis()) {
+ tree.append("Expired");
+ } else {
+ tree.append(lastAccessTime + timeToLive);
+ }
+
+ tree.append("]");
+
+ // REVISIT: is this needed for some reason?
+ // System.out.print(spaces); System.out.println("WebContinuation " + id);
+
+ int size = children.size();
+ depth++;
+
+ for (int i = 0; i < size; i++) {
+ tree.append(((WebContinuation) children.get(i)).display(depth));
+ }
+
+ return tree.toString();
+ }
+
+ /**
+ * Update the continuation in the
+ */
+ protected void updateLastAccessTime() {
+ lastAccessTime = new Date().getTime();
+ }
+
+ /**
+ * Determines whether this continuation has expired
+ *
+ * @return a <code>boolean</code> value
+ */
+ public boolean hasExpired() {
+ long currentTime = System.currentTimeMillis();
+ long expireTime = this.getLastAccessTime() + this.timeToLive;
+
+ return (currentTime > expireTime);
+ }
}