diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FileServer.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FileServer.java index 15d947a1f9e..f47b666b9a0 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FileServer.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FileServer.java @@ -32,17 +32,27 @@ public class FileServer { public static void main(String[] args) throws Exception { + // Create a basic Jetty server object that will listen on port 8080. Note that if you set this to port 0 + // then a randomly available port will be assigned that you can either look in the logs for the port, + // or programmatically obtain it for use in test cases. Server server = new Server(8080); + // Create the ResourceHandler. It is the object that will actually handle the request for a given file. It is + // a Jetty Handler object so it is suitable for chaining with other handlers as you will see in other examples. ResourceHandler resource_handler = new ResourceHandler(); + // Configure the ResourceHandler. Setting the resource base indicates where the files should be served out of. + // In this example it is the current directory but it can be configured to anything that the jvm has access to. resource_handler.setDirectoriesListed(true); resource_handler.setWelcomeFiles(new String[]{ "index.html" }); resource_handler.setResourceBase("."); - + + // Add the ResourceHandler to the server. HandlerList handlers = new HandlerList(); handlers.setHandlers(new Handler[] { resource_handler, new DefaultHandler() }); server.setHandler(handlers); + //Start things up! By using the server.join() the server thread will join with the current thread. + // See "http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html#join()" for more details. server.start(); server.join(); } diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyConnectors.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyConnectors.java index 92f5ddbc929..c68c798881c 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyConnectors.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyConnectors.java @@ -35,40 +35,63 @@ public class ManyConnectors { public static void main(String[] args) throws Exception { + // Since this example shows off SSL configuration, we need a keystore with the appropriate key. These two + // lines are purely a hack to get access to a keystore that we use in many unit tests and should probably be + // a direct path to your own keystore (used on line 29). String jetty_home = System.getProperty("jetty.home","../../jetty-distribution/target/distribution"); System.setProperty("jetty.home", jetty_home); - // The Server + // Create a basic jetty server object without declaring the port. Since we are configuring connectors + // directly we'll be setting ports on those connectors. Server server = new Server(); // HTTP Configuration + // HttpConfiguration is a collection of configuration information appropriate for http and https. The default + // scheme for http is http of course, as the default for secured http is https but + // we show setting the scheme to show it can be done. The port for secured communication is also set here. HttpConfiguration http_config = new HttpConfiguration(); http_config.setSecureScheme("https"); http_config.setSecurePort(8443); http_config.setOutputBufferSize(32768); // HTTP connector + // The first server connector we create is the one for http, passing in the http configuration we configured + // above so it can get things like the output buffer size, etc. We also set the port (8080) and configure an + // idle timeout. ServerConnector http = new ServerConnector(server,new HttpConnectionFactory(http_config)); http.setPort(8080); http.setIdleTimeout(30000); // SSL Context Factory for HTTPS and SPDY + // SSL requires a certificate so we configure a factory for ssl contents with information pointing to what + // keystore the ssl connection needs to know about. Much more configuration is available the ssl context, + // including things like choosing the particular certificate out of a keystore to be used. SslContextFactory sslContextFactory = new SslContextFactory(); sslContextFactory.setKeyStorePath(jetty_home + "/etc/keystore"); sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"); sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g"); // HTTPS Configuration + // A new HttpConfiguration object is needed for the next connector and you can pass the old one as an + // argument to effectively clone the contents. On this HttpConfiguration object we add a + // SecureRequestCustomizer which is how a new connector is able to resolve the https connection before + // handing control over to the Jetty Server. HttpConfiguration https_config = new HttpConfiguration(http_config); https_config.addCustomizer(new SecureRequestCustomizer()); // HTTPS connector + // We create a second ServerConnector, passing in the http configuration we just made along with the + // previously created ssl context factory. Next we set the port and a longer idle timeout. ServerConnector https = new ServerConnector(server, new SslConnectionFactory(sslContextFactory,"http/1.1"), new HttpConnectionFactory(https_config)); https.setPort(8443); https.setIdleTimeout(500000); + // Here you see the server having multiple connectors registered with it, now requests can flow into the server + // from both http and https urls to their respective ports and be processed accordingly by jetty. A simple + // handler is also registered with the server so the example has something to pass requests off to. + // Set the connectors server.setConnectors(new Connector[] { http, https }); diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/MinimalServlets.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/MinimalServlets.java index b508491df2d..28f68af4cfe 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/MinimalServlets.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/MinimalServlets.java @@ -32,10 +32,20 @@ public class MinimalServlets { public static void main(String[] args) throws Exception { + // Create a basic jetty server object that will listen on port 8080. Note that if you set this to port 0 + // then a randomly available port will be assigned that you can either look in the logs for the port, + // or programmatically obtain it for use in test cases. Server server = new Server(8080); + + // The ServletHandler is a dead simple way to create a context handler that is backed by an instance of a + // Servlet. This handler then needs to be registered with the Server object. ServletHandler handler = new ServletHandler(); server.setHandler(handler); + // Passing in the class for the servlet allows jetty to instantite an instance of that servlet and mount it + // on a given context path. + + // !! This is a raw Servlet, not a servlet that has been configured through a web.xml or anything like that !! handler.addServletWithMapping(HelloServlet.class,"/*"); server.start(); diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SpdyServer.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SpdyServer.java index 302f434ca7a..0c5b69edb0e 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SpdyServer.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SpdyServer.java @@ -57,6 +57,7 @@ public class SpdyServer // Setup Threadpool QueuedThreadPool threadPool = new QueuedThreadPool(512); + // Setup Jetty Server instance Server server = new Server(threadPool); server.manage(threadPool); server.setDumpAfterStart(false); @@ -73,9 +74,13 @@ public class SpdyServer config.addCustomizer(new ForwardedRequestCustomizer()); config.addCustomizer(new SecureRequestCustomizer()); config.setSendServerVersion(true); - - - // Http Connector + + + // Http Connector Setup + + // A plain HTTP connector listening on port 8080. Note that it's also possible to have port 8080 configured as + // a non SSL SPDY connector. But the specification and most browsers do not allow to use SPDY without SSL + // encryption. However some browsers allow it to be configured. HttpConnectionFactory http = new HttpConnectionFactory(config); ServerConnector httpConnector = new ServerConnector(server,http); httpConnector.setPort(8080); @@ -83,6 +88,9 @@ public class SpdyServer server.addConnector(httpConnector); // SSL configurations + + // We need a SSLContextFactory for the SSL encryption. That SSLContextFactory will be used by the SPDY + // connector. SslContextFactory sslContextFactory = new SslContextFactory(); sslContextFactory.setKeyStorePath(jetty_home + "/etc/keystore"); sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"); @@ -100,13 +108,20 @@ public class SpdyServer // Spdy Connector + + // Make sure that the required NPN implementations are available. SPDYServerConnectionFactory.checkNPNAvailable(); + // A ReferrerPushStrategy is being initialized. + // See: http://www.eclipse.org/jetty/documentation/current/spdy-configuring-push.html for more details. PushStrategy push = new ReferrerPushStrategy(); HTTPSPDYServerConnectionFactory spdy2 = new HTTPSPDYServerConnectionFactory(2,config,push); spdy2.setInputBufferSize(8192); spdy2.setInitialWindowSize(32768); + // We need a connection factory per protocol that our server is supposed to support on the NPN port. We then + // create a ServerConnector and pass in the supported factories. NPN will then be used to negotiate the + // protocol with the client. HTTPSPDYServerConnectionFactory spdy3 = new HTTPSPDYServerConnectionFactory(3,config,push); spdy2.setInputBufferSize(8192); @@ -115,12 +130,15 @@ public class SpdyServer npn.setInputBufferSize(1024); SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory,npn.getProtocol()); - + + // Setup the npn connector on port 8443 ServerConnector spdyConnector = new ServerConnector(server,ssl,npn,spdy3,spdy2,http); spdyConnector.setPort(8443); server.addConnector(spdyConnector); - + + // The following section adds some handlers, deployers and webapp providers. + // See: http://www.eclipse.org/jetty/documentation/current/advanced-embedding.html for details. // Setup handlers HandlerCollection handlers = new HandlerCollection(); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AbstractHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AbstractHandler.java index 4816db1152c..f3e7d28b7eb 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AbstractHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AbstractHandler.java @@ -55,6 +55,8 @@ public abstract class AbstractHandler extends ContainerLifeCycle implements Hand protected void doStart() throws Exception { LOG.debug("starting {}",this); + if (_server==null) + LOG.warn("No Server set for {}",this); super.doStart(); } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandlerCollection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandlerCollection.java index 6bed0599036..09ac1d4c038 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandlerCollection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandlerCollection.java @@ -142,7 +142,6 @@ public class ContextHandlerCollection extends HandlerCollection @Override public void setHandlers(Handler[] handlers) { - _contexts=null; super.setHandlers(handlers); if (isStarted()) mapContexts(); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ShutdownHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ShutdownHandler.java index 751ab8d12dc..bc9b145a8cd 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ShutdownHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ShutdownHandler.java @@ -19,11 +19,16 @@ package org.eclipse.jetty.server.handler; import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.SocketException; +import java.net.URL; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.NetworkConnector; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.util.log.Log; @@ -42,7 +47,7 @@ import org.eclipse.jetty.util.log.Logger; Server server = new Server(8080); HandlerList handlers = new HandlerList(); handlers.setHandlers(new Handler[] - { someOtherHandler, new ShutdownHandler(server,"secret password") }); + { someOtherHandler, new ShutdownHandler("secret password") }); server.setHandler(handlers); server.start(); @@ -64,18 +69,15 @@ import org.eclipse.jetty.util.log.Logger; } */ -public class ShutdownHandler extends AbstractHandler +public class ShutdownHandler extends HandlerWrapper { private static final Logger LOG = Log.getLogger(ShutdownHandler.class); private final String _shutdownToken; - - private final Server _server; - + private boolean _sendShutdownAtStart; private boolean _exitJvm = false; - /** * Creates a listener that lets the server be shut down remotely (but only from localhost). * @@ -84,16 +86,86 @@ public class ShutdownHandler extends AbstractHandler * @param shutdownToken * a secret password to avoid unauthorized shutdown attempts */ + @Deprecated public ShutdownHandler(Server server, String shutdownToken) { - this._server = server; - this._shutdownToken = shutdownToken; + this(shutdownToken); } + public ShutdownHandler(String shutdownToken) + { + this(shutdownToken,false,false); + } + + /** + * @param shutdownToken + * @param sendShutdownAtStart If true, a shutdown is sent as a HTTP post + * during startup, which will shutdown any previously running instances of + * this server with an identically configured ShutdownHandler + */ + public ShutdownHandler(String shutdownToken, boolean exitJVM, boolean sendShutdownAtStart) + { + this._shutdownToken = shutdownToken; + setExitJvm(exitJVM); + setSendShutdownAtStart(sendShutdownAtStart); + } + + + public void sendShutdown() throws IOException + { + URL url = new URL(getServerUrl() + "/shutdown?token=" + _shutdownToken); + try + { + HttpURLConnection connection = (HttpURLConnection)url.openConnection(); + connection.setRequestMethod("POST"); + connection.getResponseCode(); + LOG.info("Shutting down " + url + ": " + connection.getResponseMessage()); + } + catch (SocketException e) + { + LOG.debug("Not running"); + // Okay - the server is not running + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + @SuppressWarnings("resource") + private String getServerUrl() + { + NetworkConnector connector=null; + for (Connector c: getServer().getConnectors()) + { + if (c instanceof NetworkConnector) + { + connector=(NetworkConnector)c; + break; + } + } + + if (connector==null) + return "http://localhost"; + + return "http://localhost:" + connector.getPort(); + } + + + @Override + protected void doStart() throws Exception + { + super.doStart(); + if (_sendShutdownAtStart) + sendShutdown(); + } + + @Override public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { if (!target.equals("/shutdown")) { + super.handle(target,baseRequest,request,response); return; } @@ -117,13 +189,15 @@ public class ShutdownHandler extends AbstractHandler LOG.info("Shutting down by request from " + getRemoteAddr(request)); + final Server server=getServer(); new Thread() { + @Override public void run () { try { - shutdownServer(); + shutdownServer(server); } catch (InterruptedException e) { @@ -154,9 +228,9 @@ public class ShutdownHandler extends AbstractHandler return _shutdownToken.equals(tok); } - private void shutdownServer() throws Exception + private void shutdownServer(Server server) throws Exception { - _server.stop(); + server.stop(); if (_exitJvm) { @@ -169,4 +243,24 @@ public class ShutdownHandler extends AbstractHandler this._exitJvm = exitJvm; } + public boolean isSendShutdownAtStart() + { + return _sendShutdownAtStart; + } + + public void setSendShutdownAtStart(boolean sendShutdownAtStart) + { + _sendShutdownAtStart = sendShutdownAtStart; + } + + public String getShutdownToken() + { + return _shutdownToken; + } + + public boolean isExitJvm() + { + return _exitJvm; + } + } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ShutdownHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ShutdownHandlerTest.java index 3ffd8e3154f..d54e7cd52a1 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ShutdownHandlerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ShutdownHandlerTest.java @@ -51,8 +51,9 @@ public class ShutdownHandlerTest public void startServer() throws Exception { MockitoAnnotations.initMocks(this); + shutdownHandler = new ShutdownHandler(shutdownToken); + server.setHandler(shutdownHandler); server.start(); - shutdownHandler = new ShutdownHandler(server,shutdownToken); } @Test diff --git a/jetty-spring/src/test/resources/org/eclipse/jetty/spring/configure.xml b/jetty-spring/src/test/resources/org/eclipse/jetty/spring/configure.xml index 740e85b81d9..978c1dfc598 100644 --- a/jetty-spring/src/test/resources/org/eclipse/jetty/spring/configure.xml +++ b/jetty-spring/src/test/resources/org/eclipse/jetty/spring/configure.xml @@ -1,12 +1,13 @@ - + - - + test diff --git a/jetty-spring/src/test/resources/org/eclipse/jetty/spring/jetty.xml b/jetty-spring/src/test/resources/org/eclipse/jetty/spring/jetty.xml index 76d27fb6173..ffa485faf70 100644 --- a/jetty-spring/src/test/resources/org/eclipse/jetty/spring/jetty.xml +++ b/jetty-spring/src/test/resources/org/eclipse/jetty/spring/jetty.xml @@ -1,7 +1,8 @@ - + - diff --git a/tests/test-webapps/test-jetty-webapp/src/main/java/com/acme/ChatServlet.java b/tests/test-webapps/test-jetty-webapp/src/main/java/com/acme/ChatServlet.java index dabfacd81c9..81325d689ed 100644 --- a/tests/test-webapps/test-jetty-webapp/src/main/java/com/acme/ChatServlet.java +++ b/tests/test-webapps/test-jetty-webapp/src/main/java/com/acme/ChatServlet.java @@ -141,8 +141,7 @@ public class ChatServlet extends HttpServlet AsyncContext async = request.startAsync(); async.setTimeout(asyncTimeout); async.addListener(member); - if (!member._async.compareAndSet(null, async)) - throw new IllegalStateException(); + member._async.set(async); } } }