477123 - AsyncListener callbacks need context scope
Also added DebugListener and deprecated DebugHandler
This commit is contained in:
parent
7957ed06ef
commit
02c5ea30be
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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>
|
|
@ -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
|
|
@ -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()
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
|
@ -447,6 +447,10 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
|
|||
handleException(e);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_request.setDispatcherType(null);
|
||||
}
|
||||
|
||||
action = _state.unhandle();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue