1 // 2 // ======================================================================== 3 // Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. 4 // ------------------------------------------------------------------------ 5 // All rights reserved. This program and the accompanying materials 6 // are made available under the terms of the Eclipse Public License v1.0 7 // and Apache License v2.0 which accompanies this distribution. 8 // 9 // The Eclipse Public License is available at 10 // http://www.eclipse.org/legal/epl-v10.html 11 // 12 // The Apache License v2.0 is available at 13 // http://www.opensource.org/licenses/apache2.0.php 14 // 15 // You may elect to redistribute this code under either of these licenses. 16 // ======================================================================== 17 // 18 19 package org.eclipse.jetty.continuation; 20 21 import java.util.ArrayList; 22 import java.util.List; 23 24 import javax.servlet.ServletRequest; 25 import javax.servlet.ServletResponse; 26 import javax.servlet.ServletResponseWrapper; 27 28 import org.mortbay.log.Log; 29 import org.mortbay.log.Logger; 30 31 /* ------------------------------------------------------------ */ 32 /** 33 * This implementation of Continuation is used by {@link ContinuationSupport} 34 * when it detects that the application is deployed in a jetty-6 server. 35 * This continuation requires the {@link ContinuationFilter} to be deployed. 36 */ 37 public class Jetty6Continuation implements ContinuationFilter.FilteredContinuation 38 { 39 private static final Logger LOG = Log.getLogger(Jetty6Continuation.class.getName()); 40 41 // Exception reused for all continuations 42 // Turn on debug in ContinuationFilter to see real stack trace. 43 private final static ContinuationThrowable __exception = new ContinuationThrowable(); 44 45 private final ServletRequest _request; 46 private ServletResponse _response; 47 private final org.mortbay.util.ajax.Continuation _j6Continuation; 48 49 private Throwable _retry; 50 private int _timeout; 51 private boolean _initial=true; 52 private volatile boolean _completed=false; 53 private volatile boolean _resumed=false; 54 private volatile boolean _expired=false; 55 private boolean _responseWrapped=false; 56 private List<ContinuationListener> _listeners; 57 Jetty6Continuation(ServletRequest request, org.mortbay.util.ajax.Continuation continuation)58 public Jetty6Continuation(ServletRequest request, org.mortbay.util.ajax.Continuation continuation) 59 { 60 if (!ContinuationFilter._initialized) 61 { 62 LOG.warn("!ContinuationFilter installed",null,null); 63 throw new IllegalStateException("!ContinuationFilter installed"); 64 } 65 _request=request; 66 _j6Continuation=continuation; 67 } 68 addContinuationListener(final ContinuationListener listener)69 public void addContinuationListener(final ContinuationListener listener) 70 { 71 if (_listeners==null) 72 _listeners=new ArrayList<ContinuationListener>(); 73 _listeners.add(listener); 74 } 75 complete()76 public void complete() 77 { 78 synchronized(this) 79 { 80 if (_resumed) 81 throw new IllegalStateException(); 82 _completed=true; 83 if (_j6Continuation.isPending()) 84 _j6Continuation.resume(); 85 } 86 } 87 88 /* ------------------------------------------------------------ */ 89 /** 90 * @see org.eclipse.jetty.continuation.Continuation#getAttribute(java.lang.String) 91 */ getAttribute(String name)92 public Object getAttribute(String name) 93 { 94 return _request.getAttribute(name); 95 } 96 97 /* ------------------------------------------------------------ */ 98 /** 99 * @see org.eclipse.jetty.continuation.Continuation#removeAttribute(java.lang.String) 100 */ removeAttribute(String name)101 public void removeAttribute(String name) 102 { 103 _request.removeAttribute(name); 104 } 105 106 /* ------------------------------------------------------------ */ 107 /** 108 * @see org.eclipse.jetty.continuation.Continuation#setAttribute(java.lang.String, java.lang.Object) 109 */ setAttribute(String name, Object attribute)110 public void setAttribute(String name, Object attribute) 111 { 112 _request.setAttribute(name,attribute); 113 } 114 115 /* ------------------------------------------------------------ */ getServletResponse()116 public ServletResponse getServletResponse() 117 { 118 return _response; 119 } 120 121 /* ------------------------------------------------------------ */ isExpired()122 public boolean isExpired() 123 { 124 return _expired; 125 } 126 127 /* ------------------------------------------------------------ */ isInitial()128 public boolean isInitial() 129 { 130 return _initial; 131 } 132 133 /* ------------------------------------------------------------ */ isResumed()134 public boolean isResumed() 135 { 136 return _resumed; 137 } 138 139 /* ------------------------------------------------------------ */ isSuspended()140 public boolean isSuspended() 141 { 142 return _retry!=null; 143 } 144 145 /* ------------------------------------------------------------ */ resume()146 public void resume() 147 { 148 synchronized(this) 149 { 150 if (_completed) 151 throw new IllegalStateException(); 152 _resumed=true; 153 if (_j6Continuation.isPending()) 154 _j6Continuation.resume(); 155 } 156 } 157 158 /* ------------------------------------------------------------ */ setTimeout(long timeoutMs)159 public void setTimeout(long timeoutMs) 160 { 161 _timeout=(timeoutMs>Integer.MAX_VALUE)?Integer.MAX_VALUE:(int)timeoutMs; 162 } 163 164 /* ------------------------------------------------------------ */ 165 /** 166 * @see org.eclipse.jetty.continuation.Continuation#suspend(javax.servlet.ServletResponse) 167 */ suspend(ServletResponse response)168 public void suspend(ServletResponse response) 169 { 170 try 171 { 172 _response=response; 173 _responseWrapped=_response instanceof ServletResponseWrapper; 174 _resumed=false; 175 _expired=false; 176 _completed=false; 177 _j6Continuation.suspend(_timeout); 178 } 179 catch(Throwable retry) 180 { 181 _retry=retry; 182 } 183 } 184 185 /* ------------------------------------------------------------ */ suspend()186 public void suspend() 187 { 188 try 189 { 190 _response=null; 191 _responseWrapped=false; 192 _resumed=false; 193 _expired=false; 194 _completed=false; 195 _j6Continuation.suspend(_timeout); 196 } 197 catch(Throwable retry) 198 { 199 _retry=retry; 200 } 201 } 202 203 /* ------------------------------------------------------------ */ isResponseWrapped()204 public boolean isResponseWrapped() 205 { 206 return _responseWrapped; 207 } 208 209 /* ------------------------------------------------------------ */ 210 /** 211 * @see org.eclipse.jetty.continuation.Continuation#undispatch() 212 */ undispatch()213 public void undispatch() 214 { 215 if (isSuspended()) 216 { 217 if (ContinuationFilter.__debug) 218 throw new ContinuationThrowable(); 219 throw __exception; 220 } 221 throw new IllegalStateException("!suspended"); 222 } 223 224 /* ------------------------------------------------------------ */ enter(ServletResponse response)225 public boolean enter(ServletResponse response) 226 { 227 _response=response; 228 _expired=!_j6Continuation.isResumed(); 229 230 if (_initial) 231 return true; 232 233 _j6Continuation.reset(); 234 235 if (_expired) 236 { 237 if (_listeners!=null) 238 { 239 for (ContinuationListener l: _listeners) 240 l.onTimeout(this); 241 } 242 } 243 244 return !_completed; 245 } 246 247 /* ------------------------------------------------------------ */ exit()248 public boolean exit() 249 { 250 _initial=false; 251 252 Throwable th=_retry; 253 _retry=null; 254 if (th instanceof Error) 255 throw (Error)th; 256 if (th instanceof RuntimeException) 257 throw (RuntimeException)th; 258 259 if (_listeners!=null) 260 { 261 for (ContinuationListener l: _listeners) 262 l.onComplete(this); 263 } 264 265 return true; 266 } 267 } 268