//
// ========================================================================
-// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+// Copyright (c) 1995-2016 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
package org.eclipse.jetty.server;
import java.io.IOException;
-import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.URI;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
+
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.HandlerWrapper;
+import org.eclipse.jetty.server.handler.StatisticsHandler;
import org.eclipse.jetty.util.Attributes;
import org.eclipse.jetty.util.AttributesMap;
import org.eclipse.jetty.util.Jetty;
import org.eclipse.jetty.util.MultiException;
import org.eclipse.jetty.util.URIUtil;
+import org.eclipse.jetty.util.Uptime;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.annotation.Name;
{
return _stopAtShutdown;
}
+
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Set a graceful stop time.
+ * The {@link StatisticsHandler} must be configured so that open connections can
+ * be tracked for a graceful shutdown.
+ * @see org.eclipse.jetty.util.component.ContainerLifeCycle#setStopTimeout(long)
+ */
+ @Override
+ public void setStopTimeout(long stopTimeout)
+ {
+ super.setStopTimeout(stopTimeout);
+ }
/* ------------------------------------------------------------ */
+ /** Set stop server at shutdown behaviour.
+ * @param stop If true, this server instance will be explicitly stopped when the
+ * JVM is shutdown. Otherwise the JVM is stopped with the server running.
+ * @see Runtime#addShutdownHook(Thread)
+ * @see ShutdownThread
+ */
public void setStopAtShutdown(boolean stop)
{
//if we now want to stop
@Override
protected void doStart() throws Exception
{
+ //If the Server should be stopped when the jvm exits, register
+ //with the shutdown handler thread.
if (getStopAtShutdown())
- {
ShutdownThread.register(this);
- }
+ //Register the Server with the handler thread for receiving
+ //remote stop commands
+ ShutdownMonitor.register(this);
+
+ //Start a thread waiting to receive "stop" commands.
ShutdownMonitor.getInstance().start(); // initialize
LOG.info("jetty-" + getVersion());
// check size of thread pool
SizedThreadPool pool = getBean(SizedThreadPool.class);
int max=pool==null?-1:pool.getMaxThreads();
- int needed=1;
+ int selectors=0;
+ int acceptors=0;
if (mex.size()==0)
{
for (Connector connector : _connectors)
{
if (connector instanceof AbstractConnector)
- needed+=((AbstractConnector)connector).getAcceptors();
+ acceptors+=((AbstractConnector)connector).getAcceptors();
+
if (connector instanceof ServerConnector)
- needed+=((ServerConnector)connector).getSelectorManager().getSelectorCount();
+ selectors+=((ServerConnector)connector).getSelectorManager().getSelectorCount();
}
}
+ int needed=1+selectors+acceptors;
if (max>0 && needed>max)
- throw new IllegalStateException("Insufficient max threads in ThreadPool: max="+max+" < needed="+needed);
+ throw new IllegalStateException(String.format("Insufficient threads: max=%d < needed(acceptors=%d + selectors=%d + request=1)",max,acceptors,selectors));
try
{
mex.ifExceptionThrow();
- LOG.info(String.format("Started @%dms",ManagementFactory.getRuntimeMXBean().getUptime()));
+ LOG.info(String.format("Started @%dms",Uptime.getUptime()));
}
@Override
if (stopTimeout>0)
{
long stop_by=System.currentTimeMillis()+stopTimeout;
- LOG.debug("Graceful shutdown {} by ",this,new Date(stop_by));
+ if (LOG.isDebugEnabled())
+ LOG.debug("Graceful shutdown {} by ",this,new Date(stop_by));
// Wait for shutdowns
for (Future<Void> future: futures)
}
catch (Exception e)
{
- mex.add(e.getCause());
+ mex.add(e);
}
}
}
if (getStopAtShutdown())
ShutdownThread.deregister(this);
+
+ //Unregister the Server with the handler thread for receiving
+ //remote stop commands as we are stopped already
+ ShutdownMonitor.deregister(this);
+
mex.ifExceptionThrow();
final Response response=connection.getResponse();
if (LOG.isDebugEnabled())
- LOG.debug(request.getDispatcherType()+" "+target+" on "+connection);
+ LOG.debug(request.getDispatcherType()+" "+request.getMethod()+" "+target+" on "+connection);
- if ("*".equals(target))
+ if (HttpMethod.OPTIONS.is(request.getMethod()) || "*".equals(target))
{
+ if (!HttpMethod.OPTIONS.is(request.getMethod()))
+ response.sendError(HttpStatus.BAD_REQUEST_400);
handleOptions(request,response);
if (!request.isHandled())
handle(target, request, request, response);
*/
protected void handleOptions(Request request,Response response) throws IOException
{
- if (!HttpMethod.OPTIONS.is(request.getMethod()))
- response.sendError(HttpStatus.BAD_REQUEST_400);
- request.setHandled(true);
- response.setStatus(200);
- response.getHttpFields().put(HttpHeader.ALLOW,"GET,POST,HEAD,OPTIONS");
- response.setContentLength(0);
- response.closeOutput();
}
/* ------------------------------------------------------------ */
final Request baseRequest=connection.getRequest();
final String path=event.getPath();
-
+
if (path!=null)
{
// this is a dispatch with a path
ServletContext context=event.getServletContext();
- HttpURI uri = new HttpURI(context==null?path:URIUtil.addPaths(context.getContextPath(),path));
+ HttpURI uri = new HttpURI(URIUtil.addPaths(context==null?null:context.getContextPath(), path));
baseRequest.setUri(uri);
baseRequest.setRequestURI(null);
- baseRequest.setPathInfo(baseRequest.getRequestURI());
+ baseRequest.setPathInfo(uri.getDecodedPath());
if (uri.getQuery()!=null)
baseRequest.mergeQueryParameters(uri.getQuery(), true); //we have to assume dispatch path and query are UTF8
}
if (LOG.isDebugEnabled())
{
- LOG.debug(request.getDispatcherType()+" "+target+" on "+connection);
+ LOG.debug(request.getDispatcherType()+" "+request.getMethod()+" "+target+" on "+connection);
handle(target, baseRequest, request, response);
LOG.debug("RESPONSE "+target+" "+connection.getResponse().getStatus());
}
/**
* @return The URI of the first {@link NetworkConnector} and first {@link ContextHandler}, or null
*/
+ @SuppressWarnings("resource")
public URI getURI()
{
NetworkConnector connector=null;
return this.getClass().getName()+"@"+Integer.toHexString(hashCode());
}
+ /* ------------------------------------------------------------ */
@Override
public void dump(Appendable out,String indent) throws IOException
{