Reformatted match id and added a configuration for the service URI.

Change-Id: I94c56b42cfbe7a99095a38b6fca2e9c987d4ba3d
diff --git a/src/main/java/de/mannheim/ids/korap/sru/KorapClient.java b/src/main/java/de/mannheim/ids/korap/sru/KorapClient.java
index 00f95f9..d3ad13c 100644
--- a/src/main/java/de/mannheim/ids/korap/sru/KorapClient.java
+++ b/src/main/java/de/mannheim/ids/korap/sru/KorapClient.java
@@ -1,12 +1,14 @@
 package de.mannheim.ids.korap.sru;
 
 import java.io.BufferedInputStream;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Properties;
 
 import org.apache.http.HttpStatus;
 import org.apache.http.NameValuePair;
@@ -35,8 +37,9 @@
  */
 public class KorapClient {
 
-    private static final String SERVICE_URI = "http://localhost:8089/api/v0.1/";
-    // "http://10.0.10.13:7070/api/v0.1/";
+    private static String SERVICE_URI;
+    private static final String CONFIGURATION_FILE = "kustvakt.conf";
+    private static final String SERVICE_URI_PROPERTY = "korapsru.client.service.uri";
     private static final String DEFAULT_CONTEXT_TYPE = "sentence";
     private static final String DEFAULT_FOUNDRY = "*";
 
@@ -47,6 +50,7 @@
     private static Logger logger = (Logger) LoggerFactory
             .getLogger(KorapClient.class);
 
+
     /**
      * Constructs a KorapClient with the given number of records per
      * page and the maximum number of records.
@@ -55,12 +59,34 @@
      *            the number of records per page
      * @param maxRecords
      *            the number of maximum records/matches to retrieve
+     * @throws FileNotFoundException
      */
-    public KorapClient (int numOfRecords, int maxRecords) {
+    public KorapClient (int numOfRecords, int maxRecords)
+            throws FileNotFoundException {
         this.defaultNumOfRecords = numOfRecords;
         this.defaultMaxRecords = maxRecords;
+
+        Properties properties = new Properties();
+        InputStream is = getClass().getClassLoader()
+                .getResourceAsStream(CONFIGURATION_FILE);
+        try {
+            properties.load(is);
+        }
+        catch (IOException e) {
+            throw new FileNotFoundException("Configuration file "
+                    + CONFIGURATION_FILE + " is not found in the classpath.");
+        }
+        if (properties.containsKey(SERVICE_URI_PROPERTY)) {
+            SERVICE_URI = properties.getProperty("korapsru.client.service.uri");
+            logger.info(SERVICE_URI);
+        }
+        else {
+            throw new NullPointerException("Please specify korapsru.client."
+                    + "service.uri in the configuration file.");
+        }
     }
 
+
     /**
      * Gets information about available resources to search through
      * the KorAP public services.
@@ -70,7 +96,8 @@
      * @throws URISyntaxException
      * @throws IOException
      */
-    public JsonNode retrieveResources() throws URISyntaxException, IOException {
+    public JsonNode retrieveResources ()
+            throws URISyntaxException, IOException {
 
         URIBuilder builder = new URIBuilder(SERVICE_URI + "VirtualCollection");
         // builder.addParameter("type", "VirtualCollection");
@@ -90,12 +117,12 @@
                 logger.warn("Error response code: " + statusCode);
                 logger.warn("Error message: "
                         + response.getStatusLine().getReasonPhrase());
-                throw new HttpResponseException(statusCode, response
-                        .getStatusLine().getReasonPhrase());
+                throw new HttpResponseException(statusCode,
+                        response.getStatusLine().getReasonPhrase());
             }
 
-            BufferedInputStream jsonStream = new BufferedInputStream(response
-                    .getEntity().getContent());
+            BufferedInputStream jsonStream = new BufferedInputStream(
+                    response.getEntity().getContent());
             try {
                 resources = objectMapper.readValue(jsonStream, JsonNode.class);
             }
@@ -113,6 +140,7 @@
         return resources;
     }
 
+
     /**
      * Sends the given query to KorAP search API and creates a
      * KorapResult from the response.
@@ -134,7 +162,7 @@
      * @throws HttpResponseException
      * @throws IOException
      */
-    public KorapResult query(String query, QueryLanguage queryLanguage,
+    public KorapResult query (String query, QueryLanguage queryLanguage,
             String version, int startRecord, int maximumRecords,
             String[] corpora) throws HttpResponseException, IOException {
 
@@ -172,8 +200,8 @@
                 parseError(response);
             }
 
-            BufferedInputStream jsonStream = new BufferedInputStream(response
-                    .getEntity().getContent());
+            BufferedInputStream jsonStream = new BufferedInputStream(
+                    response.getEntity().getContent());
             try {
                 result = objectMapper.readValue(jsonStream, KorapResult.class);
             }
@@ -184,6 +212,9 @@
                 jsonStream.close();
             }
         }
+        catch (IOException e) {
+            throw new IOException("Failed executing HTTP request.",e);
+        }
         finally {
             response.close();
         }
@@ -191,18 +222,20 @@
         return result;
     }
 
+
     /**
-     * Parses the error message from Kustvakt (probably an old format).
+     * Parses the error message from Kustvakt (probably an old
+     * format).
      * 
      * @param response
      *            a response from Kustvakt
      * @throws IOException
      */
-    private static void parseError(CloseableHttpResponse response)
+    private static void parseError (CloseableHttpResponse response)
             throws IOException {
 
-        logger.warn("Error message: "
-                + response.getStatusLine().getReasonPhrase());
+        logger.warn(
+                "Error message: " + response.getStatusLine().getReasonPhrase());
 
         InputStream is = response.getEntity().getContent();
         JsonNode node = objectMapper.readTree(is);
@@ -225,6 +258,7 @@
                 errorItems[1]);
     }
 
+
     /**
      * Builds a search retrieve GET request for the given parameters.
      * 
@@ -241,7 +275,7 @@
      * @return a HttpGet request
      * @throws URISyntaxException
      */
-    private HttpGet createSearchRequest(String query,
+    private HttpGet createSearchRequest (String query,
             QueryLanguage queryLanguage, String version, int startRecord,
             int maximumRecords) throws URISyntaxException {
 
@@ -259,9 +293,10 @@
         params.add(new BasicNameValuePair("ql", queryLanguage.toString()));
         params.add(new BasicNameValuePair("v", version));
         params.add(new BasicNameValuePair("context", DEFAULT_CONTEXT_TYPE));
-        params.add(new BasicNameValuePair("count", String
-                .valueOf(maximumRecords)));
-        params.add(new BasicNameValuePair("offset", String.valueOf(startRecord)));
+        params.add(new BasicNameValuePair("count",
+                String.valueOf(maximumRecords)));
+        params.add(
+                new BasicNameValuePair("offset", String.valueOf(startRecord)));
 
         URIBuilder builder = new URIBuilder(SERVICE_URI + "search");
         builder.addParameters(params);
@@ -272,6 +307,7 @@
         return request;
     }
 
+
     /**
      * Sends a request to the MatchInfo API to get the annotations of
      * a particular match identified with corpus/resource id, document
@@ -291,8 +327,8 @@
      * @throws IOException
      * @throws URISyntaxException
      */
-    public static String retrieveAnnotations(String resourceId,
-            String documentId, String matchId, String foundry)
+    public static String retrieveAnnotations (String resourceId,
+            String documentId, String textId, String matchId, String foundry)
             throws IOException, URISyntaxException {
 
         if (resourceId == null) {
@@ -324,7 +360,7 @@
         }
 
         HttpUriRequest httpRequest;
-        httpRequest = createMatchInfoRequest(resourceId, documentId, matchId,
+        httpRequest = createMatchInfoRequest(resourceId, documentId, textId, matchId,
                 foundry);
 
         String annotationSnippet = null;
@@ -340,8 +376,8 @@
                 parseError(response);
             }
 
-            BufferedInputStream jsonStream = new BufferedInputStream(response
-                    .getEntity().getContent());
+            BufferedInputStream jsonStream = new BufferedInputStream(
+                    response.getEntity().getContent());
             try {
                 JsonNode root = objectMapper.readTree(jsonStream);
                 annotationSnippet = "<snippet>" + root.at("/snippet").asText()
@@ -361,6 +397,7 @@
         return annotationSnippet;
     }
 
+
     /**
      * Builds a request URL to send to the KorAP MatchInfo service.
      * 
@@ -375,17 +412,18 @@
      * @return a HttpGet request
      * @throws URISyntaxException
      */
-    private static HttpGet createMatchInfoRequest(String resourceId,
-            String documentId, String matchId, String foundry)
+    private static HttpGet createMatchInfoRequest (String resourceId,
+            String documentId, String textId, String matchId, String foundry)
             throws URISyntaxException {
 
         StringBuilder sb = new StringBuilder();
         sb.append(SERVICE_URI);
-        // sb.append("http://localhost:8089/api/v0.1/");
         sb.append("corpus/");
         sb.append(resourceId);
         sb.append("/");
         sb.append(documentId);
+        sb.append(".");
+        sb.append(textId);
         sb.append("/");
         sb.append(matchId);
         sb.append("/matchInfo?foundry=");
diff --git a/src/main/java/de/mannheim/ids/korap/sru/KorapMatch.java b/src/main/java/de/mannheim/ids/korap/sru/KorapMatch.java
index b5c2889..fd0c1c1 100644
--- a/src/main/java/de/mannheim/ids/korap/sru/KorapMatch.java
+++ b/src/main/java/de/mannheim/ids/korap/sru/KorapMatch.java
@@ -14,6 +14,7 @@
     private String matchID;
     private String positionId;
     private String docId;
+    private String textId;
     private String corpusId;
     private String leftContext;
     private String keyword;
@@ -23,7 +24,7 @@
 
     private List<AnnotationLayer> annotationLayers = new ArrayList<AnnotationLayer>();
     
-    private static Pattern idPattern = Pattern.compile("match-(.*)_(.*)-p([0-9]+-[0-9]+)");
+    private static Pattern idPattern = Pattern.compile("match-(.*)/(.*)/(.*)-p([0-9]+-[0-9]+)");
 
     public KorapMatch () {}
     
@@ -41,7 +42,8 @@
         if (matcher.find()){
             this.corpusId = matcher.group(1);
             this.docId = matcher.group(2);
-            this.positionId = "p"+matcher.group(3);
+            this.setTextId(matcher.group(3));
+            this.positionId = "p"+matcher.group(4);
         }
     } 
     
@@ -53,12 +55,20 @@
         return positionId;
     }
 
+    public String getTextId () {
+        return textId;
+    }
+
+    public void setTextId (String textId) {
+        this.textId = textId;
+    }
+
     public String getDocId() {
         return docId;
     }
 
     public void setDocId(String docID) {
-        this.docId = docID.replace(corpusId + "_", "");
+        this.docId = docID;
     }
 
     public String getCorpusId() {
diff --git a/src/main/java/de/mannheim/ids/korap/sru/KorapSRU.java b/src/main/java/de/mannheim/ids/korap/sru/KorapSRU.java
index 4e1c4db..59c1d65 100644
--- a/src/main/java/de/mannheim/ids/korap/sru/KorapSRU.java
+++ b/src/main/java/de/mannheim/ids/korap/sru/KorapSRU.java
@@ -1,5 +1,6 @@
 package de.mannheim.ids.korap.sru;
 
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.List;
 import java.util.Map;
@@ -55,8 +56,13 @@
             SRUQueryParserRegistry.Builder parserRegistryBuilder,
             Map<String, String> params) throws SRUConfigException {
         // serverConfig = config;
-        korapClient = new KorapClient(config.getNumberOfRecords(),
-                config.getMaximumRecords());
+        try {
+            korapClient = new KorapClient(config.getNumberOfRecords(),
+                    config.getMaximumRecords());
+        }
+        catch (FileNotFoundException e) {
+            throw new SRUConfigException(e.getMessage());
+        }
 
         StringBuilder sb = new StringBuilder();
         sb.append(config.getTransports());
diff --git a/src/main/java/de/mannheim/ids/korap/sru/KorapSRUSearchResultSet.java b/src/main/java/de/mannheim/ids/korap/sru/KorapSRUSearchResultSet.java
index 7f0d3b6..95fed85 100644
--- a/src/main/java/de/mannheim/ids/korap/sru/KorapSRUSearchResultSet.java
+++ b/src/main/java/de/mannheim/ids/korap/sru/KorapSRUSearchResultSet.java
@@ -109,7 +109,6 @@
     public void writeRecord(XMLStreamWriter writer) throws XMLStreamException {
         KorapMatch match = korapResult.getMatch(i);
         match.parseMatchId();
-
         XMLStreamWriterHelper.writeStartResource(writer, match.getMatchId(),
                 null);
         XMLStreamWriterHelper.writeStartResourceFragment(writer, null, null);
@@ -162,10 +161,10 @@
 
         try {
             String annotationSnippet = KorapClient.retrieveAnnotations(
-                    match.getCorpusId(), match.getDocId(),
+                    match.getCorpusId(), match.getDocId(), match.getTextId(),
                     match.getPositionId(), "*");
             InputStream is = new ByteArrayInputStream(
-                    annotationSnippet.getBytes());
+                    annotationSnippet.getBytes("UTF-8"));
             saxParser.parse(is, annotationHandler);
         }
         catch (SAXException | IOException | URISyntaxException e) {
diff --git a/src/main/resources/kustvakt.conf b/src/main/resources/kustvakt.conf
new file mode 100644
index 0000000..3216d34
--- /dev/null
+++ b/src/main/resources/kustvakt.conf
@@ -0,0 +1,5 @@
+# KorAP configuration file that is also used in Krill and Kustvakt.

+

+# Configuration for KorapSRU

+korapsru.client.service.uri=http://localhost:8089/api/v0.1/

+#korapsru.client.service.uri=http://10.0.10.13:7070/api/v0.1/
\ No newline at end of file