ovidiu 2003/01/08 21:40:00 Modified: src/java/org/apache/cocoon/components/flow ContinuationsManagerImpl.java ContinuationsManager.java Log: Added support for expiring continuations. Revision Changes Path 1.7 +155 -16 xml-cocoon2/src/java/org/apache/cocoon/components/flow/ContinuationsManagerImpl.java Index: ContinuationsManagerImpl.java =================================================================== RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/flow/ContinuationsManagerImpl.java,v retrieving revision 1.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- ContinuationsManagerImpl.java 6 Dec 2002 18:20:15 -0000 1.6 +++ ContinuationsManagerImpl.java 9 Jan 2003 05:40:00 -0000 1.7 @@ -51,6 +51,16 @@ import org.apache.avalon.framework.logger.AbstractLogEnabled; import org.apache.avalon.framework.thread.ThreadSafe; +import org.apache.avalon.framework.component.ComponentManager; +import org.apache.avalon.framework.component.ComponentException; +import org.apache.avalon.framework.component.Composable; + +import org.apache.avalon.framework.activity.Disposable; + +import org.apache.avalon.cornerstone.services.scheduler.TimeScheduler; +import org.apache.avalon.cornerstone.services.scheduler.Target; +import org.apache.avalon.cornerstone.services.scheduler.TimeTriggerFactory; + import java.security.SecureRandom; import java.util.*; @@ -58,21 +68,28 @@ * The default implementation of {@link ContinuationsManager}. * * @author <a href="mailto:[EMAIL PROTECTED]">Ovidiu Predescu</a> + * @author <a href="mailto:[EMAIL PROTECTED]">Michael Melhem</a> * @since March 19, 2002 * @see ContinuationsManager */ public class ContinuationsManagerImpl extends AbstractLogEnabled - implements ContinuationsManager, Component, Configurable, ThreadSafe { + implements ContinuationsManager, Component, Configurable, + ThreadSafe, Composable, Disposable, Target { static final int CONTINUATION_ID_LENGTH = 20; + static final String EXPIRE_CONTINUATIONS="expire-continuations"; + protected SecureRandom random = null; protected byte[] bytes; + protected TimeScheduler m_scheduler; + protected ComponentManager m_manager; + /** * How long does a continuation exist in memory since the last - * access? The time is in seconds, and the default is 3600 (1 hour). + * access? The time is in miliseconds, and the default is 1 hour. */ protected int defaultTimeToLive; @@ -92,7 +109,7 @@ * their expiration time. This is used by the background thread to * invalidate continuations. */ - protected SortedSet expirations = new TreeSet(); + protected SortedSet expirations = Collections.synchronizedSortedSet(new TreeSet()); public ContinuationsManagerImpl() throws Exception @@ -104,7 +121,22 @@ public void configure(Configuration config) { - defaultTimeToLive = config.getAttributeAsInteger("time-to-live", 3600); + defaultTimeToLive = config.getAttributeAsInteger("time-to-live", (3600 * 1000)); + Configuration expireConf = config.getChild("expirations-check"); + + try { + m_scheduler = (TimeScheduler)this.m_manager.lookup(TimeScheduler.ROLE); + TimeTriggerFactory triggerFac = new TimeTriggerFactory(); + + m_scheduler.addTrigger(EXPIRE_CONTINUATIONS, + triggerFac.createTimeTrigger(expireConf), + this); + } + catch (Exception ex) { + if (this.getLogger().isDebugEnabled()) { + getLogger().debug("WK: Exception while configuring WKManager " + ex); + } + } } public WebContinuation createWebContinuation(Object kont, @@ -119,7 +151,8 @@ if (parentKont == null) forrest.add(wk); - // REVISIT: Place only the "leaf" nodes in the expirations Sorted Set. + // 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()); @@ -128,14 +161,13 @@ expirations.add(wk); - if (this.getLogger().isDebugEnabled()) { - displayAllContinuations(); - displayExpireSet(); - } - // 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; } @@ -155,7 +187,7 @@ protected void _invalidate(WebContinuation wk) { if (this.getLogger().isDebugEnabled()) { - getLogger().debug("WK: Expiring Continuation " + wk.getId()); + getLogger().debug("WK: Manual Expire of Continuation " + wk.getId()); } idToWebCont.remove(wk.getId()); expirations.remove(wk); @@ -169,6 +201,8 @@ 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); } @@ -211,21 +245,63 @@ 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()); + StringBuffer wkSet = new StringBuffer("\nWK; Expire Set Size: "+ expirations.size()); while (iter.hasNext()) { final WebContinuation wk = (WebContinuation)iter.next(); - final long lat = wk.getLastAccessTime(); + final long lat = wk.getLastAccessTime() + wk.getTimeToLive(); wkSet.append("\nWK: ") .append(wk.getId()) - .append(" Last Touched [") - .append(lat) - .append("]"); + .append(" ExpireTime ["); + + if (lat < System.currentTimeMillis()) { + wkSet.append("Expired"); + } + else { + wkSet.append(lat); + } + wkSet.append("]"); } getLogger().debug(wkSet.toString()); @@ -241,5 +317,68 @@ while (iter.hasNext()) { ((WebContinuation)iter.next()).display(); } + } + + public void compose(ComponentManager manager) throws ComponentException + { + this.m_manager = manager; + } + + /** + * 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(); + } + } + + /** + * Handle cornerstone triggers + * + * @param trigger an <code>String</code> value + */ + public void targetTriggered(String trigger) + { + // Expire continuations whenever this + // trigger goes off. + if (trigger.equals(EXPIRE_CONTINUATIONS)) { + if (this.getLogger().isDebugEnabled()) { + getLogger().debug("WK: ExpireContinuations clean up triggered:"); + } + this.expireContinuations(); + } + } + + /** + * dispose of this component + */ + public void dispose() { + this.m_scheduler.removeTrigger(EXPIRE_CONTINUATIONS); + this.m_manager.release((Component)m_scheduler); + this.m_manager = null; } } 1.4 +0 -5 xml-cocoon2/src/java/org/apache/cocoon/components/flow/ContinuationsManager.java Index: ContinuationsManager.java =================================================================== RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/flow/ContinuationsManager.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- ContinuationsManager.java 12 Aug 2002 07:50:52 -0000 1.3 +++ ContinuationsManager.java 9 Jan 2003 05:40:00 -0000 1.4 @@ -42,11 +42,6 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - This software consists of voluntary contributions made by many individuals - on behalf of the Apache Software Foundation and was originally created by - Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache - Software Foundation, please see <http://www.apache.org/>. - */ package org.apache.cocoon.components.flow;
---------------------------------------------------------------------- In case of troubles, e-mail: [EMAIL PROTECTED] To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]