001: /*
002: * Copyright 2005 Joe Walker
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.directwebremoting.impl;
017:
018: import javax.servlet.http.HttpServletRequest;
019:
020: import org.apache.commons.logging.Log;
021: import org.apache.commons.logging.LogFactory;
022: import org.directwebremoting.extend.Sleeper;
023: import org.directwebremoting.util.Continuation;
024:
025: /**
026: * A Sleeper that works with Jetty Continuations
027: * @author Joe Walker [joe at getahead dot ltd dot uk]
028: */
029: public class JettyContinuationSleeper implements Sleeper {
030: /**
031: * @param request The request into which we store this as an attribute
032: */
033: public JettyContinuationSleeper(HttpServletRequest request) {
034: continuation = new Continuation(request);
035:
036: // At this point JettyContinuationSleeper is fully initialized so it is
037: // safe to allow other classes to see and use us.
038: //noinspection ThisEscapedInObjectConstruction
039: request.setAttribute(ATTRIBUTE_JETTY_CONDUIT, this );
040: }
041:
042: /**
043: * Is this a restarted continuation?
044: * @param request The request on which a Sleeper might be stored
045: * @return true if this request is from a restarted Continuation
046: */
047: public static boolean isRestart(HttpServletRequest request) {
048: return request.getAttribute(ATTRIBUTE_JETTY_CONDUIT) != null;
049: }
050:
051: /**
052: * Act on a restarted continuation by executing the onAwakening action
053: * @param request The request on which the Sleeper is stored
054: */
055: public static void restart(HttpServletRequest request) {
056: JettyContinuationSleeper sleeper = (JettyContinuationSleeper) request
057: .getAttribute(ATTRIBUTE_JETTY_CONDUIT);
058: if (sleeper == null) {
059: throw new IllegalStateException(
060: "No JettyContinuationSleeper in HttpServletRequest");
061: }
062:
063: request.removeAttribute(ATTRIBUTE_JETTY_CONDUIT);
064: sleeper.onAwakening.run();
065: }
066:
067: /* (non-Javadoc)
068: * @see org.directwebremoting.dwrp.Sleeper#goToSleep(java.lang.Runnable)
069: */
070: public void goToSleep(Runnable awakening) {
071: this .onAwakening = awakening;
072:
073: try {
074: // JETTY: throws a RuntimeException that must propagate to the container!
075: // The docs say that a value of 0 should suspend forever, but that
076: // appears not to happen (at least in 6.1.1) so we suspend for BigNum
077: continuation.suspend(Integer.MAX_VALUE);
078: } catch (Exception ex) {
079: Continuation.rethrowIfContinuation(ex);
080:
081: log.warn("Exception", ex);
082: proxy = new ThreadWaitSleeper();
083: proxy.goToSleep(onAwakening);
084: }
085: }
086:
087: /* (non-Javadoc)
088: * @see org.directwebremoting.dwrp.PollHandler.Sleeper#wakeUp()
089: */
090: public void wakeUp() {
091: if (proxy != null) {
092: proxy.wakeUp();
093: } else {
094: synchronized (continuation) {
095: if (!resumed) {
096: try {
097: continuation.resume();
098: } catch (Exception ex) {
099: log.error("Broken reflection", ex);
100: }
101:
102: resumed = true;
103: }
104: }
105: }
106: }
107:
108: /**
109: * If continuations fail, we proxy to a Thread Wait version
110: */
111: private ThreadWaitSleeper proxy = null;
112:
113: /**
114: * What we do when we are woken up
115: */
116: private Runnable onAwakening;
117:
118: /**
119: * The continuation object
120: */
121: protected final Continuation continuation;
122:
123: /**
124: * Has the continuation been restarted already?
125: */
126: protected boolean resumed = false;
127:
128: /**
129: * We remember the notify conduit so we can reuse it
130: */
131: public static final String ATTRIBUTE_JETTY_CONDUIT = "org.directwebremoting.dwrp.notifyConduit";
132:
133: /**
134: * The log stream
135: */
136: private static final Log log = LogFactory
137: .getLog(JettyContinuationSleeper.class);
138: }
|