Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Wilkins2015-09-11 02:06:23 +0000
committerGreg Wilkins2015-09-11 02:06:23 +0000
commit02c5ea30be86112f351cf3d4ad93977479101a2e (patch)
treea9e528fc31e10ff78f38afd9b38f308396a46d55 /jetty-server
parent7957ed06efd765943701d6c1c6c6496734df3470 (diff)
downloadorg.eclipse.jetty.project-02c5ea30be86112f351cf3d4ad93977479101a2e.tar.gz
org.eclipse.jetty.project-02c5ea30be86112f351cf3d4ad93977479101a2e.tar.xz
org.eclipse.jetty.project-02c5ea30be86112f351cf3d4ad93977479101a2e.zip
477123 - AsyncListener callbacks need context scope
Also added DebugListener and deprecated DebugHandler
Diffstat (limited to 'jetty-server')
-rw-r--r--jetty-server/src/main/config/etc/jetty-debug.xml36
-rw-r--r--jetty-server/src/main/config/modules/debug.mod29
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextState.java7
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/DebugListener.java334
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java4
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java221
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/Request.java8
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java23
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/handler/DebugHandler.java2
9 files changed, 584 insertions, 80 deletions
diff --git a/jetty-server/src/main/config/etc/jetty-debug.xml b/jetty-server/src/main/config/etc/jetty-debug.xml
new file mode 100644
index 0000000000..2e47a5f9ff
--- /dev/null
+++ b/jetty-server/src/main/config/etc/jetty-debug.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
+
+<!-- =============================================================== -->
+<!-- The DebugListener -->
+<!-- =============================================================== -->
+
+<Configure id="Server" class="org.eclipse.jetty.server.Server">
+ <New id="DebugListener" class="org.eclipse.jetty.server.DebugListener">
+ <Arg name="outputStream">
+ <New class="org.eclipse.jetty.util.RolloverFileOutputStream">
+ <Arg type="String"><Property name="jetty.logs" default="./logs"/>/yyyy_mm_dd.debug.log</Arg>
+ <Arg type="boolean"><Property name="jetty.debug.append" default="true"/></Arg>
+ <Arg type="int"><Property name="jetty.debug.retainDays" default="14"/></Arg>
+ <Arg>
+ <Call class="java.util.TimeZone" name="getTimeZone"><Arg><Property name="jetty.debug.timezone" default="GMT"/></Arg></Call>
+ </Arg>
+ </New>
+ </Arg>
+ <Arg name="showHeaders" type="boolean"><Property name="jetty.debug.showHeaders" default="true"/></Arg>
+ <Arg name="renameThread" type="boolean"><Property name="jetty.debug.renameThread" default="false"/></Arg>
+ <Arg name="dumpContext" type="boolean"><Property name="jetty.debug.dumpContext" default="true"/></Arg>
+ </New>
+
+ <Call name="addBean"><Arg><Ref refid="DebugListener"/></Arg></Call>
+
+ <Ref refid="DeploymentManager">
+ <Call name="addLifeCycleBinding">
+ <Arg>
+ <New class="org.eclipse.jetty.deploy.bindings.DebugListenerBinding">
+ <Arg><Ref refid="DebugListener"/></Arg>
+ </New>
+ </Arg>
+ </Call>
+ </Ref>
+</Configure>
diff --git a/jetty-server/src/main/config/modules/debug.mod b/jetty-server/src/main/config/modules/debug.mod
new file mode 100644
index 0000000000..0141699461
--- /dev/null
+++ b/jetty-server/src/main/config/modules/debug.mod
@@ -0,0 +1,29 @@
+#
+# Debug module
+#
+
+[depend]
+deploy
+
+[files]
+logs/
+
+[xml]
+etc/jetty-debug.xml
+
+[ini-template]
+
+## How many days to retain old log files
+# jetty.debug.retainDays=14
+
+## Timezone of the log entries
+# jetty.debug.timezone=GMT
+
+## Show Request/Response headers
+# jetty.debug.showHeaders=true
+
+## Rename threads while in context scope
+# jetty.debug.renameThread=false
+
+## Dump context as deployed
+# jetty.debug.dumpContext=true
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextState.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextState.java
index 483a41c50b..66e2825302 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextState.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextState.java
@@ -33,11 +33,18 @@ import org.eclipse.jetty.server.handler.ContextHandler;
public class AsyncContextState implements AsyncContext
{
+ private final HttpChannel _channel;
volatile HttpChannelState _state;
public AsyncContextState(HttpChannelState state)
{
_state=state;
+ _channel=_state.getHttpChannel();
+ }
+
+ public HttpChannel getHttpChannel()
+ {
+ return _channel;
}
HttpChannelState state()
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/DebugListener.java b/jetty-server/src/main/java/org/eclipse/jetty/server/DebugListener.java
new file mode 100644
index 0000000000..e1f6a3e36b
--- /dev/null
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/DebugListener.java
@@ -0,0 +1,334 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.server;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.Locale;
+
+import javax.servlet.AsyncEvent;
+import javax.servlet.AsyncListener;
+import javax.servlet.DispatcherType;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletRequestEvent;
+import javax.servlet.ServletRequestListener;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.server.handler.ContextHandler.Context;
+import org.eclipse.jetty.server.handler.ContextHandler.ContextScopeListener;
+import org.eclipse.jetty.util.DateCache;
+import org.eclipse.jetty.util.annotation.ManagedAttribute;
+import org.eclipse.jetty.util.annotation.ManagedObject;
+import org.eclipse.jetty.util.annotation.Name;
+import org.eclipse.jetty.util.component.AbstractLifeCycle;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+
+/** A Context Listener that produces additional debug.
+ * This listener if added to a ContextHandler, will produce additional debug information to
+ * either/or a specific log stream or the standard debug log.
+ * The events produced by {@link ServletContextListener}, {@link ServletRequestListener},
+ * {@link AsyncListener} and {@link ContextScopeListener} are logged.
+ */
+@ManagedObject("Debug Listener")
+public class DebugListener extends AbstractLifeCycle implements ServletContextListener
+{
+ private static final Logger LOG = Log.getLogger(DebugListener.class);
+ private static final DateCache __date=new DateCache("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH);
+
+ private final String _attr = String.format("__R%s@%x",this.getClass().getSimpleName(),System.identityHashCode(this));
+
+ private final PrintStream _out;
+ private boolean _renameThread;
+ private boolean _showHeaders;
+ private boolean _dumpContext;
+
+ public DebugListener()
+ {
+ this(null,false,false,false);
+ }
+
+ public DebugListener(@Name("renameThread") boolean renameThread, @Name("showHeaders") boolean showHeaders, @Name("dumpContext") boolean dumpContext)
+ {
+ this(null,renameThread,showHeaders,dumpContext);
+ }
+
+ public DebugListener(@Name("outputStream") OutputStream out, @Name("renameThread") boolean renameThread, @Name("showHeaders") boolean showHeaders, @Name("dumpContext") boolean dumpContext)
+ {
+ _out=out==null?null:new PrintStream(out);
+ _renameThread=renameThread;
+ _showHeaders=showHeaders;
+ _dumpContext=dumpContext;
+ }
+
+ @ManagedAttribute("Rename thread within context scope")
+ public boolean isRenameThread()
+ {
+ return _renameThread;
+ }
+
+ public void setRenameThread(boolean renameThread)
+ {
+ _renameThread = renameThread;
+ }
+
+ @ManagedAttribute("Show request headers")
+ public boolean isShowHeaders()
+ {
+ return _showHeaders;
+ }
+
+ public void setShowHeaders(boolean showHeaders)
+ {
+ _showHeaders = showHeaders;
+ }
+
+ @ManagedAttribute("Dump contexts at start")
+ public boolean isDumpContext()
+ {
+ return _dumpContext;
+ }
+
+ public void setDumpContext(boolean dumpContext)
+ {
+ _dumpContext = dumpContext;
+ }
+
+ @Override
+ public void contextInitialized(ServletContextEvent sce)
+ {
+ sce.getServletContext().addListener(_servletRequestListener);
+ ContextHandler handler = ContextHandler.getContextHandler(sce.getServletContext());
+ handler.addEventListener(_contextScopeListener);
+ String cname=findContextName(sce.getServletContext());
+ log("^ ctx=%s %s",cname,sce.getServletContext());
+ if (_dumpContext)
+ {
+ if (_out==null)
+ handler.dumpStdErr();
+ else
+ {
+ try
+ {
+ handler.dump(_out);
+ }
+ catch(Exception e)
+ {
+ LOG.warn(e);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void contextDestroyed(ServletContextEvent sce)
+ {
+ String cname=findContextName(sce.getServletContext());
+ log("v ctx=%s %s",cname,sce.getServletContext());
+ }
+
+ protected String findContextName(ServletContext context)
+ {
+ if (context==null)
+ return null;
+ String n = (String)context.getAttribute(_attr);
+ if (n==null)
+ {
+ n=String.format("%s@%x",context.getContextPath(),context.hashCode());
+ context.setAttribute(_attr,n);
+ }
+ return n;
+ }
+
+ protected String findRequestName(ServletRequest request)
+ {
+ if (request==null)
+ return null;
+ HttpServletRequest r = (HttpServletRequest)request;
+ String n = (String)request.getAttribute(_attr);
+ if (n==null)
+ {
+ n=String.format("%s@%x",r.getRequestURI(),request.hashCode());
+ request.setAttribute(_attr,n);
+ }
+ return n;
+ }
+
+ protected void log(String format, Object... arg)
+ {
+ if (!isRunning())
+ return;
+
+ String s=String.format(format,arg);
+
+ long now = System.currentTimeMillis();
+ long ms = now%1000;
+ if (_out!=null)
+ _out.printf("%s.%03d:%s%n",__date.formatNow(now),ms,s);
+ if (LOG.isDebugEnabled())
+ LOG.info(s);
+ }
+
+ final AsyncListener _asyncListener = new AsyncListener()
+ {
+ @Override
+ public void onTimeout(AsyncEvent event) throws IOException
+ {
+ String cname=findContextName(((AsyncContextEvent)event).getServletContext());
+ String rname=findRequestName(event.getAsyncContext().getRequest());
+ log("! ctx=%s r=%s onTimeout %s",cname,rname,((AsyncContextEvent)event).getHttpChannelState());
+ }
+
+ @Override
+ public void onStartAsync(AsyncEvent event) throws IOException
+ {
+ String cname=findContextName(((AsyncContextEvent)event).getServletContext());
+ String rname=findRequestName(event.getAsyncContext().getRequest());
+ log("! ctx=%s r=%s onStartAsync %s",cname,rname,((AsyncContextEvent)event).getHttpChannelState());
+ }
+
+ @Override
+ public void onError(AsyncEvent event) throws IOException
+ {
+ String cname=findContextName(((AsyncContextEvent)event).getServletContext());
+ String rname=findRequestName(event.getAsyncContext().getRequest());
+ log("!! ctx=%s r=%s onError %s %s",cname,rname,event.getThrowable(),((AsyncContextEvent)event).getHttpChannelState());
+ }
+
+ @Override
+ public void onComplete(AsyncEvent event) throws IOException
+ {
+ AsyncContextEvent ace=(AsyncContextEvent)event;
+ String cname=findContextName(ace.getServletContext());
+ String rname=findRequestName(ace.getAsyncContext().getRequest());
+
+ Request br=Request.getBaseRequest(ace.getAsyncContext().getRequest());
+ Response response = br.getResponse();
+ String headers=_showHeaders?("\n"+response.getHttpFields().toString()):"";
+
+ log("! ctx=%s r=%s onComplete %s %d%s",cname,rname,ace.getHttpChannelState(),response.getStatus(),headers);
+ }
+ };
+
+ final ServletRequestListener _servletRequestListener = new ServletRequestListener()
+ {
+ @Override
+ public void requestInitialized(ServletRequestEvent sre)
+ {
+ String cname=findContextName(sre.getServletContext());
+ HttpServletRequest r = (HttpServletRequest)sre.getServletRequest();
+
+ String rname=findRequestName(r);
+ DispatcherType d = r.getDispatcherType();
+ if (d==DispatcherType.REQUEST)
+ {
+ Request br=Request.getBaseRequest(r);
+
+ String headers=_showHeaders?("\n"+br.getMetaData().getFields().toString()):"";
+
+
+ StringBuffer url=r.getRequestURL();
+ if (r.getQueryString()!=null)
+ url.append('?').append(r.getQueryString());
+ log(">> %s ctx=%s r=%s %s %s %s %s %s%s",d,
+ cname,
+ rname,
+ d,
+ r.getMethod(),
+ url.toString(),
+ r.getProtocol(),
+ br.getHttpChannel(),
+ headers);
+ }
+ else
+ log(">> %s ctx=%s r=%s",d,cname,rname);
+ }
+
+ @Override
+ public void requestDestroyed(ServletRequestEvent sre)
+ {
+ String cname=findContextName(sre.getServletContext());
+ HttpServletRequest r = (HttpServletRequest)sre.getServletRequest();
+ String rname=findRequestName(r);
+ DispatcherType d = r.getDispatcherType();
+ if (sre.getServletRequest().isAsyncStarted())
+ {
+ sre.getServletRequest().getAsyncContext().addListener(_asyncListener);
+ log("<< %s ctx=%s r=%s async=true",d,cname,rname);
+ }
+ else
+ {
+ Request br=Request.getBaseRequest(r);
+ String headers=_showHeaders?("\n"+br.getResponse().getHttpFields().toString()):"";
+ log("<< %s ctx=%s r=%s async=false %d%s",d,cname,rname,Request.getBaseRequest(r).getResponse().getStatus(),headers);
+ }
+ }
+ };
+
+ final ContextHandler.ContextScopeListener _contextScopeListener = new ContextHandler.ContextScopeListener()
+ {
+ @Override
+ public void enterScope(Context context, Request request, Object reason)
+ {
+ String cname=findContextName(context);
+ if (request==null)
+ log("> ctx=%s %s",cname,reason);
+ else
+ {
+ String rname=findRequestName(request);
+
+ if (_renameThread)
+ {
+ Thread thread=Thread.currentThread();
+ thread.setName(String.format("%s#%s",thread.getName(),rname));
+ }
+
+ log("> ctx=%s r=%s %s",cname,rname,reason);
+ }
+ }
+
+
+ @Override
+ public void exitScope(Context context, Request request)
+ {
+ String cname=findContextName(context);
+ if (request==null)
+ log("< ctx=%s",cname);
+ else
+ {
+ String rname=findRequestName(request);
+
+ log("< ctx=%s r=%s",cname,rname);
+ if (_renameThread)
+ {
+ Thread thread=Thread.currentThread();
+ if (thread.getName().endsWith(rname))
+ thread.setName(thread.getName().substring(0,thread.getName().length()-rname.length()-1));
+ }
+ }
+ }
+ };
+}
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java
index 4f8cce73a0..9e02326dfc 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java
@@ -447,6 +447,10 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
handleException(e);
}
}
+ finally
+ {
+ _request.setDispatcherType(null);
+ }
action = _state.unhandle();
}
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java
index bf4af4b46e..8a2b1cb761 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java
@@ -270,23 +270,37 @@ public class HttpChannelState
_async=Async.STARTED;
_event=event;
lastAsyncListeners=_asyncListeners;
- _asyncListeners=null;
+ _asyncListeners=null;
}
if (lastAsyncListeners!=null)
{
- for (AsyncListener listener : lastAsyncListeners)
+ Runnable callback=new Runnable()
{
- try
+ @Override
+ public void run()
{
- listener.onStartAsync(event);
+ for (AsyncListener listener : lastAsyncListeners)
+ {
+ try
+ {
+ listener.onStartAsync(event);
+ }
+ catch(Exception e)
+ {
+ // TODO Async Dispatch Error
+ LOG.warn(e);
+ }
+ }
}
- catch(Exception e)
+ @Override
+ public String toString()
{
- // TODO Async Dispatch Error
- LOG.warn(e);
+ return "startAsync";
}
- }
+ };
+
+ runInContext(event,callback);
}
}
@@ -416,12 +430,17 @@ public class HttpChannelState
public void dispatch(ServletContext context, String path)
{
- boolean dispatch;
+ boolean dispatch=false;
+ AsyncContextEvent event=null;
try(Locker.Lock lock= _locker.lock())
{
+ boolean started=false;
+ event=_event;
switch(_async)
{
case STARTED:
+ started=true;
+ break;
case EXPIRING:
case ERRORED:
break;
@@ -435,27 +454,26 @@ public class HttpChannelState
if (path!=null)
_event.setDispatchPath(path);
- switch(_state)
+ if (started)
{
- case DISPATCHED:
- case ASYNC_IO:
- dispatch=false;
- break;
- case ASYNC_WAIT:
- _state=State.ASYNC_WOKEN;
- dispatch=true;
- break;
- case ASYNC_WOKEN:
- dispatch=false;
- break;
- default:
- LOG.warn("async dispatched when complete {}",this);
- dispatch=false;
- break;
+ switch(_state)
+ {
+ case DISPATCHED:
+ case ASYNC_IO:
+ case ASYNC_WOKEN:
+ break;
+ case ASYNC_WAIT:
+ _state=State.ASYNC_WOKEN;
+ dispatch=true;
+ break;
+ default:
+ LOG.warn("async dispatched when complete {}",this);
+ break;
+ }
}
}
- cancelTimeout();
+ cancelTimeout(event);
if (dispatch)
scheduleDispatch();
}
@@ -471,6 +489,7 @@ public class HttpChannelState
_async=Async.EXPIRING;
event=_event;
listeners=_asyncListeners;
+
}
if (LOG.isDebugEnabled())
@@ -478,43 +497,65 @@ public class HttpChannelState
if (listeners!=null)
{
- for (AsyncListener listener : listeners)
+ Runnable callback=new Runnable()
{
- try
+ @Override
+ public void run()
{
- listener.onTimeout(event);
+ for (AsyncListener listener : listeners)
+ {
+ try
+ {
+ listener.onTimeout(event);
+ }
+ catch(Exception e)
+ {
+ LOG.debug(e);
+ event.addThrowable(e);
+ _channel.getRequest().setAttribute(RequestDispatcher.ERROR_EXCEPTION,event.getThrowable());
+ break;
+ }
+ }
}
- catch(Exception e)
+ @Override
+ public String toString()
{
- LOG.debug(e);
- event.addThrowable(e);
- _channel.getRequest().setAttribute(RequestDispatcher.ERROR_EXCEPTION,event.getThrowable());
- break;
+ return "onTimeout";
}
- }
+ };
+
+ runInContext(event,callback);
}
boolean dispatch=false;
try(Locker.Lock lock= _locker.lock())
{
- if (_async==Async.EXPIRING)
+ switch(_async)
{
- // If the listeners did not call dispatch() or complete(),
- // then the container must generate an error.
- if (event.getThrowable()==null)
- {
- _async=Async.EXPIRED;
- _event.addThrowable(new TimeoutException("Async API violation"));
- }
- else
- {
- _async=Async.ERRORING;
- }
- if (_state==State.ASYNC_WAIT)
- {
- _state=State.ASYNC_WOKEN;
- dispatch=true;
- }
+ case EXPIRING:
+ if (event.getThrowable()==null)
+ {
+ _async=Async.EXPIRED;
+ _event.addThrowable(new TimeoutException("Async API violation"));
+ }
+ else
+ {
+ _async=Async.ERRORING;
+ }
+ break;
+
+ case COMPLETE:
+ case DISPATCH:
+ break;
+
+ default:
+ throw new IllegalStateException();
+ }
+
+ if (_state==State.ASYNC_WAIT)
+ {
+ _state=State.ASYNC_WOKEN;
+ dispatch=true;
}
}
@@ -530,11 +571,17 @@ public class HttpChannelState
{
// just like resume, except don't set _dispatched=true;
boolean handle=false;
+ AsyncContextEvent event=null;
try(Locker.Lock lock= _locker.lock())
{
+ boolean started=false;
+ event=_event;
+
switch(_async)
{
case STARTED:
+ started=true;
+ break;
case EXPIRING:
case ERRORED:
break;
@@ -542,22 +589,17 @@ public class HttpChannelState
throw new IllegalStateException(this.getStatusStringLocked());
}
_async=Async.COMPLETE;
- if (_state==State.ASYNC_WAIT)
+
+ if (started && _state==State.ASYNC_WAIT)
{
handle=true;
_state=State.ASYNC_WOKEN;
}
}
- cancelTimeout();
+ cancelTimeout(event);
if (handle)
- {
- ContextHandler handler=getContextHandler();
- if (handler!=null)
- handler.handle(_channel.getRequest(),_channel);
- else
- _channel.handle();
- }
+ runInContext(event,_channel);
}
public void errorComplete()
@@ -631,17 +673,31 @@ public class HttpChannelState
{
if (aListeners!=null)
{
- for (AsyncListener listener : aListeners)
+ Runnable callback = new Runnable()
{
- try
+ @Override
+ public void run()
{
- listener.onComplete(event);
- }
- catch(Exception e)
+ for (AsyncListener listener : aListeners)
+ {
+ try
+ {
+ listener.onComplete(event);
+ }
+ catch(Exception e)
+ {
+ LOG.warn(e);
+ }
+ }
+ }
+ @Override
+ public String toString()
{
- LOG.warn(e);
+ return "onComplete";
}
- }
+ };
+
+ runInContext(event,callback);
}
event.completed();
}
@@ -697,7 +753,6 @@ public class HttpChannelState
}
}
-
protected void scheduleDispatch()
{
_channel.execute(_channel);
@@ -717,10 +772,15 @@ public class HttpChannelState
{
event=_event;
}
+ cancelTimeout(event);
+ }
+
+ protected void cancelTimeout(AsyncContextEvent event)
+ {
if (event!=null)
event.cancelTimeoutTask();
}
-
+
public boolean isIdle()
{
try(Locker.Lock lock= _locker.lock())
@@ -779,7 +839,6 @@ public class HttpChannelState
}
}
-
public boolean isAsync()
{
try(Locker.Lock lock= _locker.lock())
@@ -805,7 +864,11 @@ public class HttpChannelState
{
event=_event;
}
+ return getContextHandler(event);
+ }
+ ContextHandler getContextHandler(AsyncContextEvent event)
+ {
if (event!=null)
{
Context context=((Context)event.getServletContext());
@@ -822,11 +885,25 @@ public class HttpChannelState
{
event=_event;
}
+ return getServletResponse(event);
+ }
+
+ public ServletResponse getServletResponse(AsyncContextEvent event)
+ {
if (event!=null && event.getSuppliedResponse()!=null)
return event.getSuppliedResponse();
return _channel.getResponse();
}
-
+
+ void runInContext(AsyncContextEvent event,Runnable runnable)
+ {
+ ContextHandler contextHandler = getContextHandler(event);
+ if (contextHandler==null)
+ runnable.run();
+ else
+ contextHandler.handle(_channel.getRequest(),runnable);
+ }
+
public Object getAttribute(String name)
{
return _channel.getRequest().getAttribute(name);
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java
index 2b32569433..d30633345a 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java
@@ -975,7 +975,7 @@ public class Request implements HttpServletRequest
@Override
public String getMethod()
{
- return _metadata.getMethod();
+ return _metadata==null?null:_metadata.getMethod();
}
/* ------------------------------------------------------------ */
@@ -1788,6 +1788,12 @@ public class Request implements HttpServletRequest
}
/* ------------------------------------------------------------ */
+ public org.eclipse.jetty.http.MetaData.Request getMetaData()
+ {
+ return _metadata;
+ }
+
+ /* ------------------------------------------------------------ */
public boolean hasMetaData()
{
return _metadata!=null;
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java
index cbdde7fae5..75a87f0e56 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java
@@ -1076,7 +1076,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
}
if (old_context != _scontext)
- enterScope(baseRequest);
+ enterScope(baseRequest,dispatch);
if (LOG.isDebugEnabled())
LOG.debug("context={}|{}|{} @ {}",baseRequest.getContextPath(),baseRequest.getServletPath(), baseRequest.getPathInfo(),this);
@@ -1184,8 +1184,9 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
/**
* @param request A request that is applicable to the scope, or null
+ * @param reason An object that indicates the reason the scope is being entered.
*/
- protected void enterScope(Request request)
+ protected void enterScope(Request request, Object reason)
{
if (!_contextListeners.isEmpty())
{
@@ -1193,7 +1194,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
{
try
{
- listener.enterScope(_scontext,request);
+ listener.enterScope(_scontext,request,reason);
}
catch(Throwable e)
{
@@ -1235,10 +1236,18 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
{
ClassLoader old_classloader = null;
Thread current_thread = null;
- Context old_context = null;
+ Context old_context = __context.get();
+
+ // Are we already in the scope?
+ if (old_context==_scontext)
+ {
+ runnable.run();
+ return;
+ }
+
+ // Nope, so enter the scope and then exit
try
{
- old_context = __context.get();
__context.set(_scontext);
// Set the classloader
@@ -1249,7 +1258,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
current_thread.setContextClassLoader(_classLoader);
}
- enterScope(request);
+ enterScope(request,runnable);
runnable.run();
}
finally
@@ -2859,7 +2868,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
* @param context The context being entered
* @param request A request that is applicable to the scope, or null
*/
- void enterScope(Context context, Request request);
+ void enterScope(Context context, Request request, Object reason);
/**
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DebugHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DebugHandler.java
index ebb71641df..be5822294f 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DebugHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DebugHandler.java
@@ -30,6 +30,7 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.server.AbstractConnector;
import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.DebugListener;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.DateCache;
@@ -42,6 +43,7 @@ import org.eclipse.jetty.util.RolloverFileOutputStream;
* Details of the request and response are written to an output stream
* and the current thread name is updated with information that will link
* to the details in that output.
+ * @deprecated Use {@link DebugListener}
*/
public class DebugHandler extends HandlerWrapper implements Connection.Listener
{

Back to the top