Added shutdown handler.

Change-Id: I36e63692937135cecf69688fbca73b2a000042e1
diff --git a/lite/Changes b/lite/Changes
index c96f8b4..97abbec 100644
--- a/lite/Changes
+++ b/lite/Changes
@@ -5,6 +5,8 @@
    - Added rewrite handler post construct (margaretha)
 07/11/2018
     - OpenJDK8u181-workaround (see Debian Bug report #911925; diewald)
+13/11/2018
+    - Added shutdown handler (margaretha)    
 
 version 0.61.0
 30/08/2018
diff --git a/lite/src/main/java/de/ids_mannheim/korap/server/KustvaktBaseServer.java b/lite/src/main/java/de/ids_mannheim/korap/server/KustvaktBaseServer.java
new file mode 100644
index 0000000..3786b11
--- /dev/null
+++ b/lite/src/main/java/de/ids_mannheim/korap/server/KustvaktBaseServer.java
@@ -0,0 +1,160 @@
+package de.ids_mannheim.korap.server;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.UUID;
+
+import javax.servlet.ServletContextListener;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.lang.ArrayUtils;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.handler.HandlerList;
+import org.eclipse.jetty.server.handler.ShutdownHandler;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.springframework.web.context.ContextLoaderListener;
+
+import com.sun.jersey.spi.spring.container.servlet.SpringServlet;
+
+import de.ids_mannheim.korap.config.KustvaktConfiguration;
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author hanl
+ * @date 01/06/2015
+ */
+public abstract class KustvaktBaseServer {
+
+    protected static KustvaktConfiguration config;
+
+    protected static String rootPackages;
+    protected static KustvaktArgs kargs;
+
+    public KustvaktBaseServer () {}
+
+    protected KustvaktArgs readAttributes (String[] args) {
+        KustvaktArgs kargs = new KustvaktArgs();
+        for (int i = 0; i < args.length; i++) {
+            switch ((args[i])) {
+                case "--spring-config":
+                    kargs.setSpringConfig(args[i + 1]);
+                    break;
+                case "--port":
+                    kargs.setPort(Integer.valueOf(args[i + 1]));
+                    break;
+                case "--help":
+                    StringBuffer b = new StringBuffer();
+
+                    b.append("Parameter description: \n")
+                            .append("--spring-config  <Spring XML configuration filename in classpath>\n")
+                            .append("--port  <Server port number>\n")
+                            .append("--help : This help menu\n");
+                    System.out.println(b.toString());
+                    System.out.println();
+                    return (KustvaktArgs) null;
+            }
+        }
+        return kargs;
+    }
+
+    protected void start ()
+            throws KustvaktException, IOException, NoSuchAlgorithmException {
+
+        if (kargs.port == -1) {
+            kargs.setPort(config.getPort());
+        }
+
+        Server server = new Server();
+
+        ServletContextHandler contextHandler =
+                new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
+        contextHandler.setContextPath("/");
+        contextHandler.setInitParameter("contextConfigLocation",
+                "classpath:" + kargs.getSpringConfig());
+
+        ServletContextListener listener = new ContextLoaderListener();
+        contextHandler.addEventListener(listener);
+
+        ServletHolder servletHolder = new ServletHolder(new SpringServlet());
+        servletHolder.setInitParameter(
+                "com.sun.jersey.config.property.packages", rootPackages);
+        servletHolder.setInitParameter(
+                "com.sun.jersey.api.json.POJOMappingFeature", "true");
+        servletHolder.setInitOrder(1);
+        contextHandler.addServlet(servletHolder, config.getBaseURL());
+
+        ServerConnector connector = new ServerConnector(server);
+        connector.setPort(kargs.port);
+        connector.setIdleTimeout(60000);
+
+        String shutdownToken = createRandomCode();
+        ShutdownHandler shutdownHandler =
+                new ShutdownHandler(shutdownToken, true, true);
+
+        FileOutputStream fos = new FileOutputStream(new File("shutdownToken"));
+        OutputStreamWriter writer =
+                new OutputStreamWriter(fos, StandardCharsets.UTF_8.name());
+        writer.write(shutdownToken);
+        writer.flush();
+        writer.close();
+
+        HandlerList handlers = new HandlerList();
+        handlers.addHandler(shutdownHandler);
+        handlers.addHandler(contextHandler);
+
+        server.setHandler(handlers);
+
+        server.setConnectors(new Connector[] { connector });
+        try {
+            server.start();
+            server.join();
+        }
+        catch (Exception e) {
+            System.out.println("Server could not be started!");
+            System.out.println(e.getMessage());
+            e.printStackTrace();
+            System.exit(-1);
+        }
+    }
+
+    @Setter
+    public static class KustvaktArgs {
+
+        @Getter
+        private String springConfig;
+        private int port;
+
+        public KustvaktArgs () {
+            this.port = -1;
+            this.springConfig = null;
+        }
+    }
+
+    public String createRandomCode () throws NoSuchAlgorithmException {
+        UUID randomUUID = UUID.randomUUID();
+        byte[] uuidBytes = randomUUID.toString().getBytes();
+        byte[] secureBytes = new byte[3];
+        SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
+        secureRandom.nextBytes(secureBytes);
+
+        byte[] bytes = ArrayUtils.addAll(uuidBytes, secureBytes);
+
+        MessageDigest md = MessageDigest.getInstance("MD5");
+        md.update(bytes);
+        byte[] digest = md.digest();
+        String code = Base64.encodeBase64URLSafeString(digest);
+        md.reset();
+        return code;
+    }
+}
diff --git a/lite/src/main/java/de/ids_mannheim/korap/server/KustvaktLiteServer.java b/lite/src/main/java/de/ids_mannheim/korap/server/KustvaktLiteServer.java
index 448d4f6..d2373d3 100644
--- a/lite/src/main/java/de/ids_mannheim/korap/server/KustvaktLiteServer.java
+++ b/lite/src/main/java/de/ids_mannheim/korap/server/KustvaktLiteServer.java
@@ -6,7 +6,6 @@
 import java.util.Properties;
 
 import de.ids_mannheim.korap.config.KustvaktConfiguration;
-import de.ids_mannheim.korap.web.KustvaktBaseServer;
 
 public class KustvaktLiteServer extends KustvaktBaseServer {
 
@@ -33,8 +32,7 @@
         config = new KustvaktConfiguration(properties);
 
         kargs.setSpringConfig("lite-config.xml");
-        rootPackages =
-                "de.ids_mannheim.korap.web";
+        rootPackages = "de.ids_mannheim.korap.web";
 
         server.start();
     }