Resolved #42 - Added close index controller.

Change-Id: I0df990b1bf2f7d7f92ac4f0e90aced584aad265e
diff --git a/core/Changes b/core/Changes
index 8ce8948..85f9f42 100644
--- a/core/Changes
+++ b/core/Changes
@@ -1,3 +1,7 @@
+# version 0.62
+18/03/2019
+   - Added close index controller (margaretha)
+
 # version 0.61.6
 06/02/2019
    - Added default foundry for structure layer (margaretha)
diff --git a/core/pom.xml b/core/pom.xml
index d07e1a4..eed745d 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -3,7 +3,7 @@
 	<modelVersion>4.0.0</modelVersion>
 	<groupId>de.ids_mannheim.korap</groupId>
 	<artifactId>Kustvakt-core</artifactId>
-	<version>0.61.6</version>
+	<version>0.62</version>
 
 	<properties>
 		<java.version>1.8</java.version>
diff --git a/core/src/main/java/de/ids_mannheim/korap/config/KustvaktConfiguration.java b/core/src/main/java/de/ids_mannheim/korap/config/KustvaktConfiguration.java
index 35c99c6..8144124 100644
--- a/core/src/main/java/de/ids_mannheim/korap/config/KustvaktConfiguration.java
+++ b/core/src/main/java/de/ids_mannheim/korap/config/KustvaktConfiguration.java
@@ -62,8 +62,6 @@
     private int validationEmaillength;
 
     private byte[] sharedSecret;
-    @Deprecated
-    private String adminToken;
     private int longTokenTTL;
     private int tokenTTL;
     private int shortTokenTTL;
@@ -107,6 +105,17 @@
         KrillProperties.setProp(properties);
     }
 
+    public KustvaktConfiguration () {}
+    
+    public void loadBasicProperties (Properties properties) {
+        port = new Integer(properties.getProperty("server.port", "8095"));
+        baseURL = properties.getProperty("kustvakt.base.url", "/api/*");
+        setSecureRandomAlgorithm(properties
+                .getProperty("security.secure.random.algorithm", "SHA1PRNG"));
+        setMessageDigestAlgorithm(
+                properties.getProperty("security.md.algorithm", "MD5"));
+    }
+    
     /**
      * loading of the properties and mapping to parameter variables
      * 
@@ -115,6 +124,8 @@
      * @throws Exception
      */
     protected void load (Properties properties) throws Exception {
+        loadBasicProperties(properties);
+        
         currentVersion = properties.getProperty("current.api.version", "v1.0");
         String supportedVersions =
                 properties.getProperty("supported.api.version", "");
@@ -122,11 +133,10 @@
         this.supportedVersions = new HashSet<>(Arrays.asList(supportedVersions.split(" ")));
         this.supportedVersions.add(currentVersion);
 
-        baseURL = properties.getProperty("kustvakt.base.url", "/api/*");
         maxhits = new Integer(properties.getProperty("maxhits", "50000"));
         returnhits = new Integer(properties.getProperty("returnhits", "50000"));
         indexDir = properties.getProperty("krill.indexDir", "");
-        port = new Integer(properties.getProperty("server.port", "8095"));
+        
         // server options
         serverHost = String
                 .valueOf(properties.getProperty("server.host", "localhost"));
@@ -169,7 +179,6 @@
 
         sharedSecret =
                 properties.getProperty("security.sharedSecret", "").getBytes();
-        adminToken = properties.getProperty("security.adminToken");
 
         longTokenTTL = TimeUtils.convertTimeToSeconds(
                 properties.getProperty("security.longTokenTTL", "100D"));
@@ -181,13 +190,6 @@
         // passcodeSaltField =
         // properties.getProperty("security.passcode.salt",
         // "accountCreation");
-        
-        setSecureRandomAlgorithm(properties
-                .getProperty("security.secure.random.algorithm", "SHA1PRNG"));
-
-        setMessageDigestAlgorithm(
-                properties.getProperty("security.md.algorithm", "MD5"));
-
     }
 
     /**
diff --git a/core/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java b/core/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java
index 446137c..e7a5195 100644
--- a/core/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java
+++ b/core/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java
@@ -165,22 +165,23 @@
      * 2000 status and error codes concerning authentication
      * 
      * Response with WWW-Authenticate header will be created 
-     * for all KustvaktExceptions with status codes 2000 or greater  
+     * for all KustvaktExceptions with status codes 2001 or greater  
      *  
      * MH: service level messages and callbacks
      */
 
-    public static final int AUTHENTICATION_FAILED = 2000;
-    public static final int LOGIN_FAILED = 2001;
-    public static final int EXPIRED = 2002;
-    public static final int BAD_CREDENTIALS = 2003;
-    public static final int ACCOUNT_NOT_CONFIRMED = 2004;
-    public static final int ACCOUNT_DEACTIVATED = 2005;
-
-    public static final int INVALID_ACCESS_TOKEN = 2006;
+    public static final int INCORRECT_ADMIN_TOKEN = 2000;
     
+    public static final int AUTHENTICATION_FAILED = 2001;
+    public static final int LOGIN_FAILED = 2002;
+    public static final int EXPIRED = 2003;
+    public static final int BAD_CREDENTIALS = 2004;
+    public static final int ACCOUNT_NOT_CONFIRMED = 2005;
+    public static final int ACCOUNT_DEACTIVATED = 2006;
+
     //    public static final int CLIENT_AUTHORIZATION_FAILED = 2013;
     public static final int AUTHORIZATION_FAILED = 2010;
+    public static final int INVALID_ACCESS_TOKEN = 2011;
 
     // 2020 - 2029 reserviert für LDAP-Fehlercodes - 21.04.17/FB
     public static final int LDAP_BASE_ERRCODE = 2020;
diff --git a/core/src/main/java/de/ids_mannheim/korap/server/KustvaktBaseServer.java b/core/src/main/java/de/ids_mannheim/korap/server/KustvaktBaseServer.java
index c5a8648..8de109b 100644
--- a/core/src/main/java/de/ids_mannheim/korap/server/KustvaktBaseServer.java
+++ b/core/src/main/java/de/ids_mannheim/korap/server/KustvaktBaseServer.java
@@ -4,6 +4,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStreamWriter;
+import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.security.NoSuchAlgorithmException;
 
@@ -18,6 +19,7 @@
 import org.eclipse.jetty.servlet.ServletHolder;
 import org.springframework.web.context.ContextLoaderListener;
 
+import com.google.common.io.Files;
 import com.sun.jersey.spi.spring.container.servlet.SpringServlet;
 
 import de.ids_mannheim.korap.config.KustvaktConfiguration;
@@ -71,6 +73,24 @@
             kargs.setPort(config.getPort());
         }
 
+        String adminToken="";
+        File f = new File("adminToken");
+        if (!f.exists()) {
+            RandomCodeGenerator random = new RandomCodeGenerator();
+            adminToken = random.createRandomCode(config);
+            FileOutputStream fos = new FileOutputStream(new File("adminToken"));
+            OutputStreamWriter writer =
+                    new OutputStreamWriter(fos, StandardCharsets.UTF_8.name());
+            writer.append("token=");
+            writer.append(adminToken);
+            writer.flush();
+            writer.close();
+        }
+        else {
+            adminToken = Files.readFirstLine(f, Charset.forName("utf-8"))
+                    .substring(6);
+        }
+
         Server server = new Server();
 
         ServletContextHandler contextHandler =
@@ -81,6 +101,7 @@
 
         ServletContextListener listener = new ContextLoaderListener();
         contextHandler.addEventListener(listener);
+        contextHandler.setInitParameter("adminToken", adminToken);
 
         ServletHolder servletHolder = new ServletHolder(new SpringServlet());
         servletHolder.setInitParameter(
@@ -94,17 +115,7 @@
         connector.setPort(kargs.port);
         connector.setIdleTimeout(60000);
 
-        RandomCodeGenerator random = new RandomCodeGenerator();
-        String shutdownToken = random.createRandomCode(config);
-        ShutdownHandler shutdownHandler = new ShutdownHandler(shutdownToken,true,false);
-
-        FileOutputStream fos = new FileOutputStream(new File("shutdownToken"));
-        OutputStreamWriter writer =
-                new OutputStreamWriter(fos, StandardCharsets.UTF_8.name());
-        writer.append("token=");
-        writer.append(shutdownToken);
-        writer.flush();
-        writer.close();
+        ShutdownHandler shutdownHandler = new ShutdownHandler(adminToken,true,true);
 
         HandlerList handlers = new HandlerList();
         handlers.addHandler(shutdownHandler);
diff --git a/core/src/main/java/de/ids_mannheim/korap/service/SearchService.java b/core/src/main/java/de/ids_mannheim/korap/service/SearchService.java
index 3a30fa2..9d2ef02 100644
--- a/core/src/main/java/de/ids_mannheim/korap/service/SearchService.java
+++ b/core/src/main/java/de/ids_mannheim/korap/service/SearchService.java
@@ -6,6 +6,7 @@
 import java.util.regex.Pattern;
 
 import javax.annotation.PostConstruct;
+import javax.servlet.ServletContext;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.UriBuilder;
@@ -283,4 +284,18 @@
     public String getCollocationBase (String query) throws KustvaktException {
         return graphDBhandler.getResponse("distCollo", "q", query);
     }
+    
+    public void closeIndexReader (String token, ServletContext context)
+            throws KustvaktException {
+
+        if (token != null && !token.isEmpty()
+                && token.equals(context.getInitParameter("adminToken"))) {
+            searchKrill.closeIndexReader();
+        }
+        else {
+            throw new KustvaktException(StatusCodes.INCORRECT_ADMIN_TOKEN,
+                    "Admin token is incorrect");
+        }
+    }
+    
 }
diff --git a/core/src/main/java/de/ids_mannheim/korap/web/SearchKrill.java b/core/src/main/java/de/ids_mannheim/korap/web/SearchKrill.java
index 4ed62d9..0e2d966 100644
--- a/core/src/main/java/de/ids_mannheim/korap/web/SearchKrill.java
+++ b/core/src/main/java/de/ids_mannheim/korap/web/SearchKrill.java
@@ -67,6 +67,15 @@
     public KrillIndex getIndex () {
         return index;
     };
+    
+    public void closeIndexReader() throws KustvaktException{
+        try {
+            index.closeReader();
+        }
+        catch (IOException e) {
+            throw new KustvaktException(500, "Failed closing index reader");
+        }
+    }
 
     /**
      * Search in the Lucene index.
diff --git a/core/src/main/java/de/ids_mannheim/korap/web/controller/SearchController.java b/core/src/main/java/de/ids_mannheim/korap/web/controller/SearchController.java
index 13a89a1..ef3b16b 100644
--- a/core/src/main/java/de/ids_mannheim/korap/web/controller/SearchController.java
+++ b/core/src/main/java/de/ids_mannheim/korap/web/controller/SearchController.java
@@ -5,6 +5,8 @@
 import java.util.Locale;
 import java.util.Set;
 
+import javax.servlet.ServletContext;
+import javax.ws.rs.FormParam;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
@@ -52,7 +54,8 @@
     private static final boolean DEBUG = false;
 
     private static Logger jlog = LogManager.getLogger(SearchController.class);
-
+    private @Context ServletContext context;
+    
     @Autowired
     private KustvaktResponseHandler kustvaktResponseHandler;
 
@@ -60,7 +63,20 @@
     private SearchService searchService;
     @Autowired
     private OAuth2ScopeService scopeService;
-
+    
+    @POST
+    @Path("{version}/index/close")
+    public Response closeIndexReader (@FormParam("token") String token){
+        try {
+            searchService.closeIndexReader(token, context);
+        }
+        catch (KustvaktException e) {
+            throw kustvaktResponseHandler.throwit(e);
+        }
+        return Response.ok().build();
+    }
+    
+    
     /**
      * Builds a json query serialization from the given parameters.
      * 
diff --git a/full/Changes b/full/Changes
index 1a147fc..7703da9 100644
--- a/full/Changes
+++ b/full/Changes
@@ -2,6 +2,9 @@
 28/02/2019
    - Removed old VC controllers and updated tests (margaretha, issue #34)
    - Updated VC access controllers (margaretha)
+19/03/2019
+  - Added close index controller (margaretha)
+
 
 # version 0.61.6
 04/02/2019
diff --git a/full/pom.xml b/full/pom.xml
index 0cf2ec3..f8bf49b 100644
--- a/full/pom.xml
+++ b/full/pom.xml
@@ -206,7 +206,7 @@
 		<dependency>
 			<groupId>de.ids_mannheim.korap</groupId>
 			<artifactId>Kustvakt-core</artifactId>
-			<version>[0.61.6,)</version>
+			<version>[0.62,)</version>
 		</dependency>
 		<!-- LDAP -->
 		<dependency>
diff --git a/full/src/main/java/de/ids_mannheim/korap/config/FullConfiguration.java b/full/src/main/java/de/ids_mannheim/korap/config/FullConfiguration.java
index 0b46164..8590db1 100644
--- a/full/src/main/java/de/ids_mannheim/korap/config/FullConfiguration.java
+++ b/full/src/main/java/de/ids_mannheim/korap/config/FullConfiguration.java
@@ -87,6 +87,10 @@
     public FullConfiguration (Properties properties) throws Exception {
         super(properties);
     }
+    
+    public FullConfiguration () {
+        super();
+    }
 
     @Override
     public void load (Properties properties) throws Exception {
diff --git a/full/src/main/java/de/ids_mannheim/korap/server/KustvaktServer.java b/full/src/main/java/de/ids_mannheim/korap/server/KustvaktServer.java
index 9b2f8ee..b3a3a6e 100644
--- a/full/src/main/java/de/ids_mannheim/korap/server/KustvaktServer.java
+++ b/full/src/main/java/de/ids_mannheim/korap/server/KustvaktServer.java
@@ -33,7 +33,8 @@
         properties.load(in);
         in.close();
         
-        config = new FullConfiguration(properties);
+        config = new FullConfiguration();
+        config.loadBasicProperties(properties);
 
 		if (kargs == null)
 			System.exit(0);
diff --git a/full/src/main/resources/kustvakt.conf b/full/src/main/resources/kustvakt.conf
index 2a5a045..7c8ec4c 100644
--- a/full/src/main/resources/kustvakt.conf
+++ b/full/src/main/resources/kustvakt.conf
@@ -94,7 +94,6 @@
 security.validation.stringLength = 150
 security.validation.emailLength = 50
 security.sharedSecret=this-is-shared-secret-code-for-JWT-Signing.It-must-contains-minimum-256-bits
-security.adminToken=adminToken
 
 ## applicable: rewrite, foundry, filter, deny
 security.rewrite.strategies=filter, foundry, rewrite
\ No newline at end of file
diff --git a/full/src/test/java/de/ids_mannheim/korap/config/SpringJerseyTest.java b/full/src/test/java/de/ids_mannheim/korap/config/SpringJerseyTest.java
index 60fb14a..b9ed11b 100644
--- a/full/src/test/java/de/ids_mannheim/korap/config/SpringJerseyTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/config/SpringJerseyTest.java
@@ -23,7 +23,7 @@
 @ContextConfiguration("classpath:test-config.xml")
 public abstract class SpringJerseyTest extends JerseyTest {
 
-    public final static String API_VERSION = "v1.1";
+    public final static String API_VERSION = "v1.0";
 
     @Autowired
     protected GenericApplicationContext applicationContext;
@@ -57,9 +57,7 @@
         return new WebAppDescriptor.Builder(classPackages)
                 .servletClass(SpringServlet.class)
                 .contextListenerClass(StaticContextLoaderListener.class)
-                // .contextListenerClass(ContextLoaderListener.class)
-                // .contextParam("contextConfigLocation",
-                // "classpath:test-config.xml")
+                .contextParam("adminToken", "secret")
                 .build();
     }
 
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/SearchControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/SearchControllerTest.java
index 0a62f9d..7e118d1 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/SearchControllerTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/SearchControllerTest.java
@@ -6,14 +6,20 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
-import javax.ws.rs.core.MediaType;
+import java.io.IOException;
 
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.apache.http.HttpStatus;
 import org.junit.Ignore;
 import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.google.common.net.HttpHeaders;
 import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.core.util.MultivaluedMapImpl;
 
 import de.ids_mannheim.korap.authentication.http.HttpAuthorizationHandler;
 import de.ids_mannheim.korap.config.Attributes;
@@ -21,14 +27,17 @@
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.query.serialize.QuerySerializer;
 import de.ids_mannheim.korap.utils.JsonUtils;
+import de.ids_mannheim.korap.web.SearchKrill;
 
 /**
  * @author hanl, margaretha
- * @lastUpdate 18/02/2019
+ * @lastUpdate 18/03/2019
  *
  */
 public class SearchControllerTest extends SpringJerseyTest {
 
+    @Autowired
+    private SearchKrill searchKrill;
     
     private JsonNode requestSearchWithFields(String fields) throws KustvaktException{
         ClientResponse response = resource().path(API_VERSION).path("search")
@@ -333,5 +342,21 @@
         assertNotEquals(0, node.path("matches").size());
         // assertEquals(10993, node.at("/meta/totalResults").asInt());
     }
+    
+    @Test
+    public void testCloseIndex () throws IOException {
+        searchKrill.getStatistics(null);
+        assertEquals(true, searchKrill.getIndex().isReaderOpen());
+
+        MultivaluedMap<String, String> m = new MultivaluedMapImpl();
+        m.add("token", "secret");
+
+        ClientResponse response = resource().path(API_VERSION).path("index")
+                .path("close").type(MediaType.APPLICATION_FORM_URLENCODED)
+                .post(ClientResponse.class, m);
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(false, searchKrill.getIndex().isReaderOpen());
+    }
 
 }
diff --git a/full/src/test/resources/kustvakt-test.conf b/full/src/test/resources/kustvakt-test.conf
index a4f8467..066377c 100644
--- a/full/src/test/resources/kustvakt-test.conf
+++ b/full/src/test/resources/kustvakt-test.conf
@@ -13,7 +13,7 @@
 
 # Kustvakt
 # multiple versions separated by space
-current.api.version = v1.1
+current.api.version = v1.0
 supported.api.version = v0.1 v1.0
 
 ## server
diff --git a/lite/Changes b/lite/Changes
index aa4374e..1bc17e8 100644
--- a/lite/Changes
+++ b/lite/Changes
@@ -1,3 +1,7 @@
+version 0.62
+19/03/2019
+  - Added close index controller (margaretha)  
+
 version 0.61.3
 05/02/2019
   - Updated kustvakt-lite.conf (margaretha)
diff --git a/lite/pom.xml b/lite/pom.xml
index 0753db9..a830c0c 100644
--- a/lite/pom.xml
+++ b/lite/pom.xml
@@ -3,7 +3,7 @@
 	<modelVersion>4.0.0</modelVersion>
 	<groupId>de.ids_mannheim.korap</groupId>
 	<artifactId>Kustvakt-lite</artifactId>
-	<version>0.61.3</version>
+	<version>0.62</version>
 	<properties>
 		<java.version>1.8</java.version>
 		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -137,7 +137,7 @@
 		<dependency>
 			<groupId>de.ids_mannheim.korap</groupId>
 			<artifactId>Kustvakt-core</artifactId>
-			<version>[0.61.6,)</version>
+			<version>[0.62,)</version>
 		</dependency>
 		<!-- Jersey test framework -->
 		<dependency>
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 d2373d3..c1b533f 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
@@ -29,7 +29,8 @@
 
         properties.load(in);
         in.close();
-        config = new KustvaktConfiguration(properties);
+        config = new KustvaktConfiguration();
+        config.loadBasicProperties(properties);
 
         kargs.setSpringConfig("lite-config.xml");
         rootPackages = "de.ids_mannheim.korap.web";
diff --git a/lite/src/test/java/de/ids_mannheim/korap/config/LiteJerseyTest.java b/lite/src/test/java/de/ids_mannheim/korap/config/LiteJerseyTest.java
new file mode 100644
index 0000000..bef92bf
--- /dev/null
+++ b/lite/src/test/java/de/ids_mannheim/korap/config/LiteJerseyTest.java
@@ -0,0 +1,78 @@
+package de.ids_mannheim.korap.config;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.util.concurrent.ThreadLocalRandom;
+
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.support.GenericApplicationContext;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.web.context.support.GenericWebApplicationContext;
+
+import com.sun.jersey.spi.spring.container.servlet.SpringServlet;
+import com.sun.jersey.test.framework.AppDescriptor;
+import com.sun.jersey.test.framework.JerseyTest;
+import com.sun.jersey.test.framework.WebAppDescriptor;
+import com.sun.jersey.test.framework.spi.container.TestContainerException;
+import com.sun.jersey.test.framework.spi.container.TestContainerFactory;
+import com.sun.jersey.test.framework.spi.container.grizzly.web.GrizzlyWebTestContainerFactory;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration("classpath:test-config.xml")
+public abstract class LiteJerseyTest extends JerseyTest{
+    
+    public static final String API_VERSION = "v1.0";
+    
+    @Autowired
+    protected GenericApplicationContext applicationContext;
+    
+    private static String[] classPackages =
+            new String[] { "de.ids_mannheim.korap.web.controller",
+                    "de.ids_mannheim.korap.web.filter",
+                    "de.ids_mannheim.korap.web.utils" };
+    
+    @Override
+    protected TestContainerFactory getTestContainerFactory ()
+            throws TestContainerException {
+        return new GrizzlyWebTestContainerFactory();
+    }
+
+    @Override
+    public void setUp () throws Exception {
+
+        GenericWebApplicationContext genericContext =
+                new GenericWebApplicationContext();
+
+        genericContext.setParent(this.applicationContext);
+        genericContext.setClassLoader(this.applicationContext.getClassLoader());
+
+        StaticContextLoaderListener.applicationContext = genericContext;
+        super.setUp();
+    }
+    
+    @Override
+    protected AppDescriptor configure () {
+        return new WebAppDescriptor.Builder(classPackages)
+                .servletClass(SpringServlet.class)
+                .contextListenerClass(StaticContextLoaderListener.class)
+                .contextParam("adminToken", "secret")
+                .build();
+    }
+
+    @Override
+    protected int getPort (int defaultPort) {
+        int port = ThreadLocalRandom.current().nextInt(5000, 8000 + 1);
+        try {
+            ServerSocket socket = new ServerSocket(port);
+            socket.close();
+        }
+        catch (IOException e) {
+            e.printStackTrace();
+            port = getPort(port);
+        }
+        return port;
+    }
+    
+}
diff --git a/lite/src/test/java/de/ids_mannheim/korap/config/StaticContextLoaderListener.java b/lite/src/test/java/de/ids_mannheim/korap/config/StaticContextLoaderListener.java
new file mode 100644
index 0000000..578c94e
--- /dev/null
+++ b/lite/src/test/java/de/ids_mannheim/korap/config/StaticContextLoaderListener.java
@@ -0,0 +1,22 @@
+package de.ids_mannheim.korap.config;
+
+import org.springframework.web.context.ContextLoaderListener;
+import org.springframework.web.context.WebApplicationContext;
+
+/**
+ * A hack to inject the application context generated by
+ * SpringJUnit4ClassRunner in the test suite.
+ * 
+ * @author margaretha
+ *
+ */
+public class StaticContextLoaderListener extends ContextLoaderListener {
+
+    public static WebApplicationContext applicationContext;
+
+    public StaticContextLoaderListener () {
+        super(applicationContext);
+    }
+
+
+}
diff --git a/lite/src/test/java/de/ids_mannheim/korap/web/service/LiteJerseyTest.java b/lite/src/test/java/de/ids_mannheim/korap/web/service/LiteJerseyTest.java
deleted file mode 100644
index a0ea0a3..0000000
--- a/lite/src/test/java/de/ids_mannheim/korap/web/service/LiteJerseyTest.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package de.ids_mannheim.korap.web.service;
-
-import java.io.IOException;
-import java.net.ServerSocket;
-import java.util.concurrent.ThreadLocalRandom;
-
-import org.springframework.web.context.ContextLoaderListener;
-
-import com.sun.jersey.spi.spring.container.servlet.SpringServlet;
-import com.sun.jersey.test.framework.AppDescriptor;
-import com.sun.jersey.test.framework.JerseyTest;
-import com.sun.jersey.test.framework.WebAppDescriptor;
-import com.sun.jersey.test.framework.spi.container.TestContainerException;
-import com.sun.jersey.test.framework.spi.container.TestContainerFactory;
-import com.sun.jersey.test.framework.spi.container.grizzly.web.GrizzlyWebTestContainerFactory;
-
-public class LiteJerseyTest  extends JerseyTest{
-
-    public static final String API_VERSION = "v1.0";
-    private static String[] classPackages =
-            new String[] { "de.ids_mannheim.korap.web.controller",
-                    "de.ids_mannheim.korap.web.filter",
-                    "de.ids_mannheim.korap.web.utils" };
-    @Override
-    protected TestContainerFactory getTestContainerFactory ()
-            throws TestContainerException {
-        return new GrizzlyWebTestContainerFactory();
-    }
-
-    @Override
-    protected AppDescriptor configure () {
-        return new WebAppDescriptor.Builder(classPackages)
-                .servletClass(SpringServlet.class)
-                .contextListenerClass(ContextLoaderListener.class)
-                .contextParam("contextConfigLocation",
-                        "classpath:test-config.xml")
-                .build();
-    }
-
-    @Override
-    protected int getPort (int defaultPort) {
-        int port = ThreadLocalRandom.current().nextInt(5000, 8000 + 1);
-        try {
-            ServerSocket socket = new ServerSocket(port);
-            socket.close();
-        }
-        catch (IOException e) {
-            e.printStackTrace();
-            port = getPort(port);
-        }
-        return port;
-    }
-    
-}
diff --git a/lite/src/test/java/de/ids_mannheim/korap/web/service/LiteSearchControllerTest.java b/lite/src/test/java/de/ids_mannheim/korap/web/service/LiteSearchControllerTest.java
index b30b626..7bd2409 100644
--- a/lite/src/test/java/de/ids_mannheim/korap/web/service/LiteSearchControllerTest.java
+++ b/lite/src/test/java/de/ids_mannheim/korap/web/service/LiteSearchControllerTest.java
@@ -6,26 +6,35 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
+import java.io.IOException;
 import java.net.URI;
 import java.util.Iterator;
 
 import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
 
 import org.eclipse.jetty.http.HttpStatus;
 import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.google.common.net.HttpHeaders;
 import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.core.util.MultivaluedMapImpl;
 
 import de.ids_mannheim.korap.authentication.http.HttpAuthorizationHandler;
 import de.ids_mannheim.korap.config.Attributes;
+import de.ids_mannheim.korap.config.LiteJerseyTest;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.query.serialize.QuerySerializer;
 import de.ids_mannheim.korap.utils.JsonUtils;
+import de.ids_mannheim.korap.web.SearchKrill;
 
 public class LiteSearchControllerTest extends LiteJerseyTest {
 
+    @Autowired
+    private SearchKrill searchKrill;
+    
     @Test
     public void testGetJSONQuery () throws KustvaktException {
         ClientResponse response = resource().path(API_VERSION).path("query")
@@ -374,4 +383,20 @@
         JsonNode node = JsonUtils.readTree(entity);
         assertTrue(node.at("/collection").isMissingNode());
     }
+    
+    @Test
+    public void testCloseIndex () throws IOException {
+        searchKrill.getStatistics(null);
+        assertEquals(true, searchKrill.getIndex().isReaderOpen());
+
+        MultivaluedMap<String, String> m = new MultivaluedMapImpl();
+        m.add("token", "secret");
+
+        ClientResponse response = resource().path(API_VERSION).path("index")
+                .path("close").type(MediaType.APPLICATION_FORM_URLENCODED)
+                .post(ClientResponse.class, m);
+
+        assertEquals(HttpStatus.OK_200, response.getStatus());
+        assertEquals(false, searchKrill.getIndex().isReaderOpen());
+    }
 }
diff --git a/lite/src/test/java/de/ids_mannheim/korap/web/service/LiteStatisticControllerTest.java b/lite/src/test/java/de/ids_mannheim/korap/web/service/LiteStatisticControllerTest.java
index 0efc39e..3956acd 100644
--- a/lite/src/test/java/de/ids_mannheim/korap/web/service/LiteStatisticControllerTest.java
+++ b/lite/src/test/java/de/ids_mannheim/korap/web/service/LiteStatisticControllerTest.java
@@ -7,6 +7,7 @@
 import com.fasterxml.jackson.databind.JsonNode;
 import com.sun.jersey.api.client.ClientResponse;
 
+import de.ids_mannheim.korap.config.LiteJerseyTest;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.utils.JsonUtils;