477123 - AsyncListener callbacks need context scope

Also added DebugListener and deprecated DebugHandler
This commit is contained in:
Greg Wilkins 2015-09-11 12:06:23 +10:00
parent 7957ed06ef
commit 02c5ea30be
16 changed files with 684 additions and 97 deletions

View File

@ -24,10 +24,12 @@ import java.lang.management.ManagementFactory;
import org.eclipse.jetty.deploy.DeploymentManager;
import org.eclipse.jetty.deploy.PropertiesConfigurationManager;
import org.eclipse.jetty.deploy.bindings.DebugListenerBinding;
import org.eclipse.jetty.deploy.providers.WebAppProvider;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.jmx.MBeanContainer;
import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.server.DebugListener;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
@ -155,6 +157,9 @@ public class LikeJettyXml
// === jetty-deploy.xml ===
DeploymentManager deployer = new DeploymentManager();
DebugListener debug = new DebugListener(System.out,true,true,true);
server.addBean(debug);
deployer.addLifeCycleBinding(new DebugListenerBinding(debug));
deployer.setContexts(contexts);
deployer.setContextAttribute(
"org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",

View File

@ -0,0 +1,53 @@
//
// ========================================================================
// 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.deploy.bindings;
import org.eclipse.jetty.deploy.App;
import org.eclipse.jetty.deploy.graph.Node;
import org.eclipse.jetty.server.DebugListener;
/** A Deployment binding that installs a DebugListener in all deployed contexts
*/
public class DebugListenerBinding extends DebugBinding
{
final DebugListener _debugListener;
public DebugListenerBinding()
{
this(new DebugListener());
}
public DebugListenerBinding(DebugListener debugListener)
{
super(new String[]{"deploying"});
_debugListener=debugListener;
}
public DebugListener getDebugListener()
{
return _debugListener;
}
public void processBinding(Node node, App app) throws Exception
{
app.getContextHandler().addEventListener(_debugListener);
}
}

View File

@ -257,7 +257,7 @@ public class WebAppProvider extends ScanningAppProvider
if (resource.exists() && FileID.isXmlFile(file))
{
XmlConfiguration xmlc = new XmlConfiguration(resource.getURL())
XmlConfiguration xmlc = new XmlConfiguration(resource.getURI().toURL())
{
@Override
public void initializeDefaults(Object context)

View File

@ -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>

View File

@ -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

View File

@ -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()

View File

@ -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));
}
}
}
};
}

View File

@ -447,6 +447,10 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
handleException(e);
}
}
finally
{
_request.setDispatcherType(null);
}
action = _state.unhandle();
}

View File

@ -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);

View File

@ -975,7 +975,7 @@ public class Request implements HttpServletRequest
@Override
public String getMethod()
{
return _metadata.getMethod();
return _metadata==null?null:_metadata.getMethod();
}
/* ------------------------------------------------------------ */
@ -1787,6 +1787,12 @@ public class Request implements HttpServletRequest
setPathInfo(info);
}
/* ------------------------------------------------------------ */
public org.eclipse.jetty.http.MetaData.Request getMetaData()
{
return _metadata;
}
/* ------------------------------------------------------------ */
public boolean hasMetaData()
{

View File

@ -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);
/**

View File

@ -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
{

View File

@ -87,7 +87,7 @@ public class AsyncIOServletTest
context.addEventListener(new ContextHandler.ContextScopeListener()
{
@Override
public void enterScope(Context context, Request request)
public void enterScope(Context context, Request request, Object reason)
{
if (scope.get()!=null)
throw new IllegalStateException();

View File

@ -50,6 +50,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.DebugListener;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.Server;
@ -83,6 +84,7 @@ public class AsyncServletIOTest
_server.setConnectors(new Connector[]{ _connector });
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/ctx");
context.addEventListener(new DebugListener());
_server.setHandler(context);
_servletHandler=context.getServletHandler();

View File

@ -44,6 +44,7 @@ import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.DebugListener;
import org.eclipse.jetty.server.QuietServletException;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.RequestLog;
@ -101,6 +102,7 @@ public class AsyncServletTest
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
context.setContextPath("/ctx");
logHandler.setHandler(context);
context.addEventListener(new DebugListener());
_servletHandler=context.getServletHandler();
ServletHolder holder=new ServletHolder(_servlet);

View File

@ -374,42 +374,49 @@ public class WebAppClassLoader extends URLClassLoader
String tmp = name;
if (tmp != null && tmp.endsWith(".class"))
tmp = tmp.substring(0, tmp.length()-6);
boolean system_class=_context.isSystemClass(tmp);
boolean server_class=_context.isServerClass(tmp);
if (LOG.isDebugEnabled())
LOG.debug("getResource({}) system={} server={} cl={}",name,system_class,server_class,this);
if (system_class && server_class)
return null;
ClassLoader source=null;
if (_parent!=null &&(_context.isParentLoaderPriority() || system_class ) && !server_class)
{
tried_parent= true;
if (_parent!=null)
url= _parent.getResource(name);
{
source=_parent;
url=_parent.getResource(name);
}
}
if (url == null)
{
url= this.findResource(name);
source=this;
if (url == null && name.startsWith("/"))
{
if (LOG.isDebugEnabled())
LOG.debug("HACK leading / off " + name);
url= this.findResource(name.substring(1));
}
}
if (url == null && !tried_parent && !server_class )
{
if (_parent!=null)
{
tried_parent=true;
source=_parent;
url= _parent.getResource(name);
}
}
if (url != null)
if (LOG.isDebugEnabled())
LOG.debug("getResource("+name+")=" + url);
if (LOG.isDebugEnabled())
LOG.debug("gotResource({})=={} from={} tried_parent={}",name,url,source,tried_parent);
return url;
}
@ -434,6 +441,11 @@ public class WebAppClassLoader extends URLClassLoader
boolean system_class=_context.isSystemClass(name);
boolean server_class=_context.isServerClass(name);
if (LOG.isDebugEnabled())
LOG.debug("loadClass({}) system={} server={} cl={}",name,system_class,server_class,this);
ClassLoader source=null;
if (system_class && server_class)
{
return null;
@ -442,6 +454,7 @@ public class WebAppClassLoader extends URLClassLoader
if (c == null && _parent!=null && (_context.isParentLoaderPriority() || system_class) && !server_class)
{
tried_parent= true;
source=_parent;
try
{
c= _parent.loadClass(name);
@ -458,6 +471,7 @@ public class WebAppClassLoader extends URLClassLoader
{
try
{
source=this;
c= this.findClass(name);
}
catch (ClassNotFoundException e)
@ -467,20 +481,24 @@ public class WebAppClassLoader extends URLClassLoader
}
if (c == null && _parent!=null && !tried_parent && !server_class )
{
tried_parent=true;
source=_parent;
c= _parent.loadClass(name);
}
if (c == null && ex!=null)
{
LOG.debug("not found {} from {}",name,this,ex);
LOG.debug("!loadedClass({}) from={} tried_parent={}",name,this,tried_parent);
throw ex;
}
if (LOG.isDebugEnabled())
LOG.debug("loadedClass({})=={} from={} tried_parent={}",name,c,source,tried_parent);
if (resolve)
resolveClass(c);
if (LOG.isDebugEnabled())
LOG.debug("loaded {} from {}",c,c==null?null:c.getClassLoader());
return c;
}
}
@ -541,7 +559,10 @@ public class WebAppClassLoader extends URLClassLoader
{
content = url.openStream();
byte[] bytes = IO.readBytes(content);
if (LOG.isDebugEnabled())
LOG.debug("foundClass({}) url={} cl={}",name,url,this);
for (ClassFileTransformer transformer : _transformers)
{
byte[] tmp = transformer.transform(this,name,null,null,bytes);