aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-application/src
diff options
context:
space:
mode:
authorJulien HENRY <julien.henry@sonarsource.com>2013-03-14 09:21:34 +0100
committerJulien HENRY <julien.henry@sonarsource.com>2013-03-14 09:21:54 +0100
commit86ffe2dbd5bc065d2c3312c48d4d0c5fd8fd1de1 (patch)
tree3be00c3a2cbcf43528934009d76d933c6ee09fb4 /sonar-application/src
parent5c099b6733143cd647012e0f53d78e1c2698c92b (diff)
downloadsonarqube-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.java15
-rw-r--r--sonar-application/src/main/java/org/sonar/application/ShutdownHandler.java132
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,&quot;secret password&quot;) });
+ 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;
+ }
+
+}