diff options
author | Julien HENRY <julien.henry@sonarsource.com> | 2013-03-14 09:21:34 +0100 |
---|---|---|
committer | Julien HENRY <julien.henry@sonarsource.com> | 2013-03-14 09:21:54 +0100 |
commit | 86ffe2dbd5bc065d2c3312c48d4d0c5fd8fd1de1 (patch) | |
tree | 3be00c3a2cbcf43528934009d76d933c6ee09fb4 /sonar-application/src | |
parent | 5c099b6733143cd647012e0f53d78e1c2698c92b (diff) | |
download | sonarqube-86ffe2dbd5bc065d2c3312c48d4d0c5fd8fd1de1.tar.gz sonarqube-86ffe2dbd5bc065d2c3312c48d4d0c5fd8fd1de1.zip |
SONAR-4202 Provide a way to stop Sonar Server programmatically
Diffstat (limited to 'sonar-application/src')
-rw-r--r-- | sonar-application/src/main/java/org/sonar/application/JettyEmbedder.java | 15 | ||||
-rw-r--r-- | sonar-application/src/main/java/org/sonar/application/ShutdownHandler.java | 132 |
2 files changed, 146 insertions, 1 deletions
diff --git a/sonar-application/src/main/java/org/sonar/application/JettyEmbedder.java b/sonar-application/src/main/java/org/sonar/application/JettyEmbedder.java index 55c6639a85e..98da317bedf 100644 --- a/sonar-application/src/main/java/org/sonar/application/JettyEmbedder.java +++ b/sonar-application/src/main/java/org/sonar/application/JettyEmbedder.java @@ -20,8 +20,10 @@ package org.sonar.application; import org.apache.commons.io.FileUtils; +import org.mortbay.jetty.Handler; import org.mortbay.jetty.NCSARequestLog; import org.mortbay.jetty.Server; +import org.mortbay.jetty.handler.HandlerList; import org.mortbay.jetty.handler.RequestLogHandler; import org.mortbay.jetty.nio.SelectChannelConnector; import org.mortbay.jetty.webapp.WebAppContext; @@ -89,7 +91,18 @@ public class JettyEmbedder { private Server configureProgrammatically() throws URISyntaxException { configureServer(); WebAppContext context = new WebAppContext(getPath("/war/sonar-server"), contextPath); - server.addHandler(context); + String shutdownCookie = System.getProperty("sonar.shutdownToken"); + if (shutdownCookie != null && !"".equals(shutdownCookie)) { + System.out.println("Registering shutdown handler"); + ShutdownHandler shutdownHandler = new ShutdownHandler(server, shutdownCookie); + shutdownHandler.setExitJvm(true); + HandlerList handlers = new HandlerList(); + handlers.setHandlers(new Handler[] {shutdownHandler, context}); + server.setHandler(handlers); + } + else { + server.addHandler(context); + } return server; } diff --git a/sonar-application/src/main/java/org/sonar/application/ShutdownHandler.java b/sonar-application/src/main/java/org/sonar/application/ShutdownHandler.java new file mode 100644 index 00000000000..1ca1f485e12 --- /dev/null +++ b/sonar-application/src/main/java/org/sonar/application/ShutdownHandler.java @@ -0,0 +1,132 @@ +package org.sonar.application; + +import org.mortbay.jetty.Server; +import org.mortbay.jetty.handler.AbstractHandler; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import java.io.IOException; + +/* ------------------------------------------------------------ */ +/** + * TODO Duplicate code from Jetty 8 waiting for upgrade. + * + * + * A handler that shuts the server down on a valid request. Used to do "soft" restarts from Java. If _exitJvm ist set to true a hard System.exit() call is being + * made. + * + * This handler is a contribution from Johannes Brodwall: https://bugs.eclipse.org/bugs/show_bug.cgi?id=357687 + * + * Usage: + * + * <pre> + Server server = new Server(8080); + HandlerList handlers = new HandlerList(); + handlers.setHandlers(new Handler[] + { someOtherHandler, new ShutdownHandler(server,"secret password") }); + server.setHandler(handlers); + server.start(); + </pre> + * + <pre> + public static void attemptShutdown(int port, String shutdownCookie) { + try { + URL url = new URL("http://localhost:" + port + "/shutdown?token=" + shutdownCookie); + HttpURLConnection connection = (HttpURLConnection)url.openConnection(); + connection.setRequestMethod("POST"); + connection.getResponseCode(); + logger.info("Shutting down " + url + ": " + connection.getResponseMessage()); + } catch (SocketException e) { + logger.debug("Not running"); + // Okay - the server is not running + } catch (IOException e) { + throw new RuntimeException(e); + } + } + </pre> + */ +public class ShutdownHandler extends AbstractHandler { + + private final String _shutdownToken; + + private final Server _server; + + private boolean _exitJvm = false; + + /** + * Creates a listener that lets the server be shut down remotely (but only from localhost). + * + * @param server + * the Jetty instance that should be shut down + * @param shutdownToken + * a secret password to avoid unauthorized shutdown attempts + */ + public ShutdownHandler(Server server, String shutdownToken) { + this._server = server; + this._shutdownToken = shutdownToken; + } + + public void handle(String target, HttpServletRequest request, HttpServletResponse response, + int dispatch) throws IOException, ServletException { + if (!target.equals("/shutdown")) { + return; + } + + if (!request.getMethod().equals("POST")) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST); + return; + } + if (!hasCorrectSecurityToken(request)) { + System.err.println("Unauthorized shutdown attempt from " + getRemoteAddr(request)); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED); + return; + } + if (!requestFromLocalhost(request)) { + System.err.println("Unauthorized shutdown attempt from " + getRemoteAddr(request)); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED); + return; + } + + System.out.println("Shutting down by request from " + getRemoteAddr(request)); + + new Thread() { + public void run() { + try { + shutdownServer(); + } catch (InterruptedException e) { + // Ignored + } catch (Exception e) { + throw new RuntimeException("Shutting down server", e); + } + } + }.start(); + } + + private boolean requestFromLocalhost(HttpServletRequest request) { + return "127.0.0.1".equals(getRemoteAddr(request)); + } + + protected String getRemoteAddr(HttpServletRequest request) { + return request.getRemoteAddr(); + } + + private boolean hasCorrectSecurityToken(HttpServletRequest request) { + return _shutdownToken.equals(request.getParameter("token")); + } + + private void shutdownServer() throws Exception { + _server.stop(); + + if (_exitJvm) + { + System.exit(0); + } + } + + public void setExitJvm(boolean exitJvm) { + this._exitJvm = exitJvm; + } + +} |