Added trunk, tags, branches.
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..9adfb72
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,79 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>de.mannheim.ids</groupId>
+ <artifactId>KorapSRU</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ <packaging>war</packaging>
+
+ <name>KorapSRU</name>
+ <url>http://maven.apache.org</url>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.1</version>
+ <configuration>
+ <source>1.7</source>
+ <target>1.7</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>eu.clarin.sru.fcs</groupId>
+ <artifactId>fcs-simple-endpoint</artifactId>
+ <version>1.2.0</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>2.5</version>
+ <type>jar</type>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient</artifactId>
+ <version>4.3.3</version>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ <version>2.2.3</version>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <version>1.7.6</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.directory.studio</groupId>
+ <artifactId>org.apache.commons.lang</artifactId>
+ <version>2.6</version>
+ </dependency>
+ </dependencies>
+
+ <repositories>
+ <repository>
+ <id>clarin</id>
+ <url>http://catalog.clarin.eu/ds/nexus/content/repositories/Clarin/</url>
+ <layout>default</layout>
+ </repository>
+ </repositories>
+</project>
diff --git a/src/main/java/de/mannheim/ids/korap/sru/KorapClient.java b/src/main/java/de/mannheim/ids/korap/sru/KorapClient.java
new file mode 100644
index 0000000..eecdcb3
--- /dev/null
+++ b/src/main/java/de/mannheim/ids/korap/sru/KorapClient.java
@@ -0,0 +1,252 @@
+package de.mannheim.ids.korap.sru;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.apache.http.HttpStatus;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.HttpResponseException;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.message.BasicNameValuePair;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.SAXException;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class KorapClient {
+
+ private static final String SERVICE_URI = "http://10.0.10.13:8888/api/v0.1/";
+ private String QUERY_LANGUAGE = "CQL";
+ private String CONTEXT_TYPE = "sentence";
+
+ private int defaultNumOfRecords;
+ private int defaultMaxRecords;
+
+ private ObjectMapper objectMapper;
+ private SAXParserFactory saxParserFactory;
+ private Logger logger = (Logger) LoggerFactory.getLogger(KorapClient.class);
+
+ public KorapClient(int numOfRecords, int maxRecords) {
+ objectMapper = new ObjectMapper();
+ saxParserFactory = SAXParserFactory.newInstance();
+
+ this.defaultNumOfRecords = numOfRecords;
+ this.defaultMaxRecords = maxRecords;
+ }
+
+ public JsonNode retrieveResources() throws HttpResponseException, Exception{
+
+ URIBuilder builder = new URIBuilder(SERVICE_URI+"VirtualCollection");
+ //builder.addParameter("type", "VirtualCollection");
+ URI uri = builder.build();
+ logger.info("Resource URI: "+ uri.toString());
+ HttpGet httpRequest = new HttpGet(uri);
+
+ CloseableHttpClient client = HttpClients.createDefault();
+ CloseableHttpResponse response = null;
+ JsonNode resources;
+
+ try {
+ response = client.execute(httpRequest);
+
+ int statusCode = response.getStatusLine().getStatusCode();
+ if (statusCode != HttpStatus.SC_OK){
+ logger.warn("Error response code: "+statusCode);
+ logger.warn("Error message: "+response.getStatusLine().getReasonPhrase());
+ throw new HttpResponseException(statusCode,
+ response.getStatusLine().getReasonPhrase()
+ );
+ }
+
+ BufferedInputStream jsonStream = new BufferedInputStream(
+ response.getEntity().getContent() );
+ try {
+ resources = objectMapper.readValue(jsonStream, JsonNode.class);
+ } catch (JsonParseException e) {
+ throw new Exception("Failed parsing JSON.");
+ } catch (JsonMappingException e) {
+ throw new Exception("Failed mapping JSON.");
+ }
+ finally{
+ jsonStream.close();
+ }
+ }
+ finally{
+ response.close();
+ }
+
+ return resources;
+ }
+
+
+ public KorapResult query(String query, String version, int startRecord,
+ int maximumRecords, String[] corpora) throws HttpResponseException, Exception{
+
+ checkQuery(query, startRecord, maximumRecords);
+
+ HttpUriRequest httpRequest = null;
+
+ /*if (corpora != null){
+ // create virtual collection
+ logger.info("Select collection");
+ CollectionQuery collectionQuery = new CollectionQuery()
+ .addMetaFilter("corpusID", DEFAULT_COLLECTION);
+
+ logger.info("create JsonLD");
+ QuerySerializer ss = new QuerySerializer()
+ .setQuery(query, QUERY_LANGUAGE,version)
+ .setCollection(collectionQuery)
+ .setMeta(CONTEXT_TYPE, CONTEXT_TYPE,
+ CONTEXT_SIZE, CONTEXT_SIZE, 5, startRecord-1);
+
+ String jsonld=ss.build();
+ logger.info(jsonld);
+
+ HttpPost post = new HttpPost(SERVICE_URI+"_raw");
+ post.setEntity(new StringEntity(jsonld));
+ httpRequest = post;
+ }
+ else {*/
+
+ try {
+ httpRequest = createRequest(query, version, startRecord-1,
+ maximumRecords);
+ } catch (URISyntaxException e) {
+ throw new IOException("Failed creating http request.");
+ }
+ //}
+
+ CloseableHttpClient client = HttpClients.createDefault();
+ CloseableHttpResponse response = null;
+ KorapResult result = null;
+ try {
+ response = client.execute(httpRequest);
+
+ int statusCode = response.getStatusLine().getStatusCode();
+ if (statusCode != HttpStatus.SC_OK){
+ logger.warn("Error response code: "+statusCode);
+ logger.warn("Error message: "+response.getStatusLine().getReasonPhrase());
+ String[] errorMsg = parseError(response);
+ logger.warn(errorMsg[0] +"#" +errorMsg[1]);
+ throw new HttpResponseException(Integer.parseInt(errorMsg[0]),
+ errorMsg[1]);
+ }
+
+ BufferedInputStream jsonStream = new BufferedInputStream(
+ response.getEntity().getContent() );
+ try {
+ result = objectMapper.readValue(jsonStream, KorapResult.class);
+ } catch (JsonParseException e) {
+ throw new Exception("Failed parsing JSON.");
+ } catch (JsonMappingException e) {
+ throw new Exception("Failed mapping JSON.");
+ }
+ finally{
+ jsonStream.close();
+ }
+ }
+ finally{
+ response.close();
+ }
+
+ try {
+ logger.info("Matches size: "+ result.getMatches().size());
+ logger.debug("Parsing snippets");
+ parseMatchSnippets(result);
+
+ } catch (ParserConfigurationException | SAXException e) {
+ throw new Exception("Failed parsing snippet.");
+ }
+
+ return result;
+ }
+
+ private String[] parseError(CloseableHttpResponse response)
+ throws IOException{
+ InputStream is = response.getEntity().getContent();
+ JsonNode node = objectMapper.readTree(is);
+ String message = node.get("error").textValue();
+ String[] errorItems = message.split(":",2);
+ errorItems[0] = errorItems[0].replace("SRU diagnostic ", "");
+ errorItems[1] = errorItems[1].trim();
+ return errorItems;
+ }
+
+ private void parseMatchSnippets(KorapResult result)
+ throws ParserConfigurationException, SAXException, IOException {
+
+ String snippet;
+ InputStream is;
+ SAXParser saxParser = saxParserFactory.newSAXParser();
+ for (KorapMatch m : result.getMatches()){
+ snippet = "<snippet>"+m.getSnippet()+"</snippet>";
+ is = new ByteArrayInputStream(snippet.getBytes());
+ saxParser.parse(is, new KorapMatchHandler(m));
+ //logger.info("left {}, key {}, right {} ", m.getLeftContext(), m.getKeyword(), m.getRightContext());
+ }
+ }
+
+ private HttpGet createRequest(String query, String version, int startRecord,
+ int maximumRecords)
+ throws URISyntaxException {
+
+ if (maximumRecords <= 0) {
+ maximumRecords = defaultNumOfRecords;
+ } else if (maximumRecords > defaultMaxRecords) {
+ logger.info("limit truncated from {} to {}", maximumRecords,
+ defaultMaxRecords);
+ maximumRecords = defaultMaxRecords;
+ }
+
+ List<NameValuePair> params = new ArrayList<NameValuePair>();
+ params.add(new BasicNameValuePair("q", query));
+ params.add(new BasicNameValuePair("ql", QUERY_LANGUAGE));
+ params.add(new BasicNameValuePair("v", version));
+ params.add(new BasicNameValuePair("context", CONTEXT_TYPE));
+ 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);
+ URI uri = builder.build();
+ logger.info("Query URI: "+ uri.toString());
+ HttpGet request = new HttpGet(uri);
+ return request;
+ }
+
+ private void checkQuery(String query, int startRecord, int maxRecord) {
+ if (query == null) {
+ throw new NullPointerException("Query == null.");
+ }
+ if (query.isEmpty()) {
+ throw new IllegalArgumentException("Query is empty.");
+ }
+ if (startRecord < 1) {
+ throw new IllegalArgumentException("Start record begins from 1.");
+ }
+ if (maxRecord < 1) {
+ throw new IllegalArgumentException("Maximum records is too low.");
+ }
+ }
+}
diff --git a/src/main/java/de/mannheim/ids/korap/sru/KorapJsonQuery.java b/src/main/java/de/mannheim/ids/korap/sru/KorapJsonQuery.java
new file mode 100644
index 0000000..0483a12
--- /dev/null
+++ b/src/main/java/de/mannheim/ids/korap/sru/KorapJsonQuery.java
@@ -0,0 +1,112 @@
+package de.mannheim.ids.korap.sru;
+
+public class KorapJsonQuery {
+
+ String collection;
+ String query, queryLanguage, version;
+ String lCtx, rCtx;
+ int lCtxs, rCtxs;
+ int startIndex, pageLength;
+
+ public KorapJsonQuery(String query, String collection, String lang,
+ String version, int lCtxs, int rCtxs, int startIndex, int pageLength) {
+ this(query, collection, lang, version, "token", "token", lCtxs, rCtxs,
+ startIndex, pageLength);
+ }
+
+ public KorapJsonQuery(String query, String collection, String queryLanguage,
+ String version, String lCtx, String rCtx, int lCtxs, int rCtxs,
+ int startIndex, int pageLength) {
+ this.query = query;
+ this.collection = collection;
+ this.queryLanguage = queryLanguage;
+ this.version = version;
+ this.lCtx = lCtx;
+ this.rCtx = rCtx;
+ this.lCtxs = lCtxs;
+ this.rCtxs = rCtxs;
+ this.startIndex = startIndex;
+ this.pageLength = pageLength;
+ }
+
+ public String getCollection() {
+ return collection;
+ }
+
+ public void setCollection(String collection) {
+ this.collection = collection;
+ }
+
+ public String getQuery() {
+ return query;
+ }
+
+ public void setQuery(String query) {
+ this.query = query;
+ }
+
+ public String getQueryLanguage() {
+ return queryLanguage;
+ }
+
+ public void setQueryLanguage(String queryLanguage) {
+ this.queryLanguage = queryLanguage;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ public String getlCtx() {
+ return lCtx;
+ }
+
+ public void setlCtx(String lCtx) {
+ this.lCtx = lCtx;
+ }
+
+ public String getrCtx() {
+ return rCtx;
+ }
+
+ public void setrCtx(String rCtx) {
+ this.rCtx = rCtx;
+ }
+
+ public int getlCtxs() {
+ return lCtxs;
+ }
+
+ public void setlCtxs(int lCtxs) {
+ this.lCtxs = lCtxs;
+ }
+
+ public int getrCtxs() {
+ return rCtxs;
+ }
+
+ public void setrCtxs(int rCtxs) {
+ this.rCtxs = rCtxs;
+ }
+
+ public int getPageLength() {
+ return pageLength;
+ }
+
+ public void setPageLength(int pageLength) {
+ this.pageLength = pageLength;
+ }
+
+ public int getStartIndex() {
+ return startIndex;
+ }
+
+ public void setStartIndex(int startIndex) {
+ this.startIndex = startIndex;
+ }
+
+}
diff --git a/src/main/java/de/mannheim/ids/korap/sru/KorapMatch.java b/src/main/java/de/mannheim/ids/korap/sru/KorapMatch.java
new file mode 100644
index 0000000..d70ec35
--- /dev/null
+++ b/src/main/java/de/mannheim/ids/korap/sru/KorapMatch.java
@@ -0,0 +1,65 @@
+package de.mannheim.ids.korap.sru;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class KorapMatch {
+
+ private String docID;
+ private String leftContext;
+ private String keyword;
+ private String rightContext;
+ private String snippet;
+
+ public KorapMatch() {}
+
+ public KorapMatch(String source, String leftContext, String keyword,
+ String rightContext) {
+ this.docID = source;
+ this.leftContext = leftContext;
+ this.keyword = keyword;
+ this.rightContext = rightContext;
+ }
+
+
+ public String getDocID() {
+ return docID;
+ }
+
+ public void setDocID(String docID) {
+ this.docID = docID;
+ }
+
+ public String getLeftContext() {
+ return leftContext;
+ }
+
+ public String getKeyword() {
+ return keyword;
+ }
+
+ public String getRightContext() {
+ return rightContext;
+ }
+
+ public void setLeftContext(String leftContext) {
+ this.leftContext = leftContext;
+ }
+
+ public void setKeyword(String keyword) {
+ this.keyword = keyword;
+ }
+
+ public void setRightContext(String rightContext) {
+ this.rightContext = rightContext;
+ }
+
+ public String getSnippet() {
+ return snippet;
+ }
+
+ public void setSnippet(String snippet) {
+ this.snippet = snippet;
+ }
+
+}
diff --git a/src/main/java/de/mannheim/ids/korap/sru/KorapMatchHandler.java b/src/main/java/de/mannheim/ids/korap/sru/KorapMatchHandler.java
new file mode 100644
index 0000000..952fca3
--- /dev/null
+++ b/src/main/java/de/mannheim/ids/korap/sru/KorapMatchHandler.java
@@ -0,0 +1,78 @@
+package de.mannheim.ids.korap.sru;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+public class KorapMatchHandler extends DefaultHandler{
+
+ KorapMatch match;
+ boolean isLeftContext, isRightContext, isKeyword, isMore;
+ private StringBuilder sbLeft, sbRight, sbKey;
+
+ public KorapMatchHandler(KorapMatch m) {
+ match = m;
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName,
+ Attributes attributes) throws SAXException {
+ super.startElement(uri, localName, qName, attributes);
+
+ if (qName.equals("span") && attributes.getQName(0).equals("class")){
+ switch (attributes.getValue(0)) {
+ case "context-left":
+ isLeftContext = true;
+ sbLeft = new StringBuilder();
+ break;
+ case "context-right":
+ isRightContext = true;
+ sbRight = new StringBuilder();
+ break;
+ case "match":
+ isKeyword = true;
+ sbKey = new StringBuilder();
+ break;
+ case "more":
+ isMore = true;
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName)
+ throws SAXException {
+
+ if (qName.equals("span")){
+ if (isMore){
+ isMore = false;
+ }
+ else if (isLeftContext){
+ match.setLeftContext(sbLeft.toString());
+ isLeftContext = false;
+ }
+ else if (isKeyword){
+ match.setKeyword(sbKey.toString());
+ isKeyword = false;
+ }
+ else if (isRightContext){
+ match.setRightContext(sbRight.toString());
+ isRightContext = false;
+ }
+ }
+ }
+
+ @Override
+ public void characters(char ch[], int start, int length) throws SAXException {
+ if (isKeyword){
+ sbKey.append(ch, start, length);
+ }
+ else if (isLeftContext){
+ sbLeft.append(ch, start, length);
+ }
+ else if (isRightContext){
+ sbRight.append(ch, start, length);
+ }
+ }
+}
diff --git a/src/main/java/de/mannheim/ids/korap/sru/KorapResult.java b/src/main/java/de/mannheim/ids/korap/sru/KorapResult.java
new file mode 100644
index 0000000..e5d9f91
--- /dev/null
+++ b/src/main/java/de/mannheim/ids/korap/sru/KorapResult.java
@@ -0,0 +1,40 @@
+package de.mannheim.ids.korap.sru;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class KorapResult {
+ int totalResults;
+ List<KorapMatch> matches;
+
+ public KorapResult() {
+ matches = new ArrayList<KorapMatch>();
+ }
+
+ public int getTotalResults() {
+ return totalResults;
+ }
+ public List<KorapMatch> getMatches() {
+ return matches;
+ }
+ public void setTotalResults(int totalResults) {
+ this.totalResults = totalResults;
+ }
+ public void setMatches(List<KorapMatch> matches) {
+ this.matches = matches;
+ }
+
+ public KorapMatch getMatch(int i){
+ if (i>=0 && i< getSize())
+ return matches.get(i);
+
+ return null;
+ }
+
+ public int getSize(){
+ return matches.size();
+ }
+}
diff --git a/src/main/java/de/mannheim/ids/korap/sru/KorapSRU.java b/src/main/java/de/mannheim/ids/korap/sru/KorapSRU.java
new file mode 100644
index 0000000..15e2791
--- /dev/null
+++ b/src/main/java/de/mannheim/ids/korap/sru/KorapSRU.java
@@ -0,0 +1,276 @@
+package de.mannheim.ids.korap.sru;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.apache.http.client.HttpResponseException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.z3950.zing.cql.CQLNode;
+import org.z3950.zing.cql.CQLTermNode;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+import eu.clarin.sru.server.SRUConfigException;
+import eu.clarin.sru.server.SRUConstants;
+import eu.clarin.sru.server.SRUDiagnosticList;
+import eu.clarin.sru.server.SRUException;
+import eu.clarin.sru.server.SRURequest;
+import eu.clarin.sru.server.SRUSearchResultSet;
+import eu.clarin.sru.server.SRUServerConfig;
+import eu.clarin.sru.server.SRUVersion;
+import eu.clarin.sru.server.fcs.ResourceInfo;
+import eu.clarin.sru.server.fcs.ResourceInfoInventory;
+import eu.clarin.sru.server.fcs.SimpleEndpointSearchEngineBase;
+import eu.clarin.sru.server.fcs.XMLStreamWriterHelper;
+import eu.clarin.sru.server.fcs.utils.SimpleResourceInfoInventory;
+
+/**
+ * @author margaretha
+ * */
+public class KorapSRU extends SimpleEndpointSearchEngineBase{
+
+// private static final String RESOURCE_INFO_INVENTORY_URL =
+// "/WEB-INF/resource-info.xml";
+ private static final String CLARIN_FCS_RECORD_SCHEMA =
+ "http://clarin.eu/fcs/1.0";
+ private static final String KORAP_WEB_URL =
+ "http://korap.ids-mannheim.de/app/#!login";
+
+ private KorapClient korapClient;
+ private SRUServerConfig serverConfig;
+ private String redirectBaseURI;
+
+ private Logger logger = (Logger) LoggerFactory.getLogger(KorapSRU.class);
+
+ @Override
+ protected ResourceInfoInventory createResourceInfoInventory(
+ ServletContext context, SRUServerConfig config,
+ Map<String, String> params) throws SRUConfigException {
+
+ List<ResourceInfo> resourceList = new ArrayList<ResourceInfo>();
+
+ List<String> languages = new ArrayList<String>();
+ languages.add("deu");
+
+ /*Locale locale = new Locale.Builder().setRegion("DE").build();
+ for (Locale l : locale.getAvailableLocales()){
+ if (l.getCountry().equals("DE"))
+ logger.info("locale "+l.getISO3Language());
+ }*/
+
+ Map<String,String> title;
+ Map<String,String> description;
+ try {
+ JsonNode resources = korapClient.retrieveResources();
+ for (JsonNode r : resources){
+ title = new HashMap<String,String>();
+ title.put("de", r.get("name").asText());
+ title.put("en", r.get("name").asText());
+
+ description = new HashMap<String,String>();
+ description.put("de", r.get("description").asText());
+
+ ResourceInfo ri = new ResourceInfo(
+ r.get("id").asText(), -1, title, description,
+ KORAP_WEB_URL, languages , null);
+ resourceList.add(ri);
+ }
+
+ } catch (Exception e) {
+ throw new SRUConfigException(
+ "error initializing resource info inventory", e);
+ }
+ return new SimpleResourceInfoInventory(resourceList, false);
+ }
+
+ @Override
+ protected void doInit(ServletContext context, SRUServerConfig config,
+ Map<String, String> params) throws SRUConfigException {
+
+ serverConfig = config;
+ korapClient = new KorapClient(config.getNumberOfRecords(),
+ config.getMaximumRecords());
+
+ StringBuilder sb = new StringBuilder();
+ sb.append(config.getTransports());
+ sb.append("://");
+ sb.append(config.getHost());
+ if (config.getPort() != 80) {
+ sb.append(":").append(config.getPort());
+ }
+ sb.append("/").append(config.getDatabase());
+ sb.append("/").append("redirect/");
+ this.redirectBaseURI = sb.toString();
+ }
+
+ private Map<String, String> createLocaleMap(){
+ // country,language
+ Map<String, String> map = new HashMap<String,String>();
+ Locale locale = new Locale("en");
+ for (String country : locale.getISOCountries()){
+ for (Locale l : locale.getAvailableLocales()){
+ if (l.getCountry().equals(country)){
+ map.put(country, l.getISO3Language());
+ }
+ }
+ }
+ return map;
+ }
+
+ @Override
+ public SRUSearchResultSet search(SRUServerConfig config,
+ SRURequest request, SRUDiagnosticList diagnostics)
+ throws SRUException {
+
+ checkSchema(request);
+
+ String korapQuery = translateCQLtoKorapQuery(request.getQuery());
+ String version = null;
+ if (request.isVersion(SRUVersion.VERSION_1_1)){
+ version = "1.1";
+ }
+ else if (request.isVersion(SRUVersion.VERSION_1_2)){
+ version = "1.2";
+ }
+ else {
+ serverConfig.getDefaultVersion();
+ }
+
+ KorapResult result = null;
+ try {
+ result = korapClient.query(
+ korapQuery,
+ version,
+ request.getStartRecord(),
+ request.getMaximumRecords(),
+ getCorporaList(request)
+ );
+ }
+ catch (HttpResponseException e) {
+ logger.warn("HttpResponseException: " +e.getStatusCode()+" "+e.getMessage());
+ switch (e.getStatusCode()) {
+ case 16:
+ throw new SRUException(SRUConstants.SRU_UNSUPPORTED_INDEX,
+ e.getMessage());
+ case 19:
+ throw new SRUException(SRUConstants.SRU_UNSUPPORTED_RELATION,
+ e.getMessage());
+ case 20:
+ throw new SRUException(SRUConstants.SRU_UNSUPPORTED_RELATION_MODIFIER,
+ e.getMessage());
+ case 27:
+ throw new SRUException(SRUConstants.SRU_EMPTY_TERM_UNSUPPORTED,
+ e.getMessage());
+ case 48 :
+ throw new SRUException(SRUConstants.SRU_QUERY_FEATURE_UNSUPPORTED,
+ e.getMessage());
+ default:
+ throw new SRUException(SRUConstants.SRU_GENERAL_SYSTEM_ERROR);
+ }
+
+ }
+ catch (Exception e) {
+ throw new SRUException(SRUConstants.SRU_GENERAL_SYSTEM_ERROR);
+ }
+
+ return generateSRUResultSet(diagnostics, result);
+ }
+
+ private String[] getCorporaList(SRURequest request){
+ try {
+ String corpusPids = request.getExtraRequestData("x-fcs-context");
+ if (!corpusPids.isEmpty() && corpusPids != null){
+ if (corpusPids.contains(",")){
+ return corpusPids.split(",");
+ }
+ return new String[]{corpusPids};
+ }
+ return null;
+ }
+ catch (NullPointerException e) {
+ return null;
+ }
+ }
+
+
+ private String translateCQLtoKorapQuery(CQLNode query) throws SRUException {
+ String queryStr = query.toString();
+ if ((queryStr == null) || queryStr.isEmpty()) {
+ throw new SRUException(SRUConstants.SRU_EMPTY_TERM_UNSUPPORTED,
+ "An empty term is not supported.");
+ }
+ return queryStr;
+ }
+
+ private void checkSchema(SRURequest request) throws SRUException{
+ final String recordSchemaIdentifier =
+ request.getRecordSchemaIdentifier();
+ if ((recordSchemaIdentifier != null) &&
+ !recordSchemaIdentifier.equals(CLARIN_FCS_RECORD_SCHEMA)) {
+ throw new SRUException(
+ SRUConstants.SRU_UNKNOWN_SCHEMA_FOR_RETRIEVAL,
+ recordSchemaIdentifier, "Record schema \"" +
+ recordSchemaIdentifier +
+ "\" is not supported by this endpoint.");
+ }
+ }
+
+ private SRUSearchResultSet generateSRUResultSet(SRUDiagnosticList diagnostics,
+ final KorapResult result) {
+
+ return new SRUSearchResultSet(diagnostics) {
+
+ private int i = -1;
+
+ @Override
+ public void writeRecord(XMLStreamWriter writer) throws XMLStreamException {
+ KorapMatch match = result.getMatch(i);
+ XMLStreamWriterHelper.writeResourceWithKWICDataView(writer,
+ match.getDocID(), redirectBaseURI + match.getDocID(),
+ match.getLeftContext(), match.getKeyword(),
+ match.getRightContext()
+ );
+// FCSResultWriter.writeResource(writer,
+// // pid, ref
+// "", redirectBaseURI + match.getDocID(),
+// match.getLeftContext(), match.getKeyword(),
+// match.getRightContext()
+// );
+ //logger.info("left {}, key {}, right {} ", match.getLeftContext(), match.getKeyword(), match.getRightContext());
+ }
+
+ @Override
+ public boolean nextRecord() throws SRUException {
+ return (++i < result.getSize() ? true : false );
+ }
+
+ @Override
+ public int getTotalRecordCount() {
+ return result.getTotalResults();
+ }
+
+ @Override
+ public String getRecordSchemaIdentifier() {
+ return CLARIN_FCS_RECORD_SCHEMA;
+ }
+
+ @Override
+ public String getRecordIdentifier() {
+ return null;
+ }
+
+ @Override
+ public int getRecordCount() {
+ return result.getSize();
+ }
+ };
+ }
+}
diff --git a/src/main/webapp/META-INF/MANIFEST.MF b/src/main/webapp/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..254272e
--- /dev/null
+++ b/src/main/webapp/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Class-Path:
+
diff --git a/src/main/webapp/WEB-INF/resource-info.xml b/src/main/webapp/WEB-INF/resource-info.xml
new file mode 100644
index 0000000..dedb24c
--- /dev/null
+++ b/src/main/webapp/WEB-INF/resource-info.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ResourceCollection xmlns="http://clarin.eu/fcs/1.0/resource-info">
+ <ResourceInfo pid="Wikipedia">
+ <Title xml:lang="de">Wikipedia</Title>
+ <Title xml:lang="en">Wikipedia</Title>
+ <Description xml:lang="de">
+ The German Wikipedia.
+ </Description>
+ <Description xml:lang="en">
+ The German Wikipedia.
+ </Description>
+ <LandingPageURI>http://korap.ids-mannheim.de/app/#!login</LandingPageURI>
+ <Languages>
+ <Language>deu</Language>
+ </Languages>
+ </ResourceInfo>
+</ResourceCollection>
diff --git a/src/main/webapp/WEB-INF/sru-server-config.xml b/src/main/webapp/WEB-INF/sru-server-config.xml
new file mode 100644
index 0000000..45be806
--- /dev/null
+++ b/src/main/webapp/WEB-INF/sru-server-config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<endpoint-config xmlns="http://www.clarin.eu/sru-server/1.0/">
+ <databaseInfo>
+ <title xml:lang="de">KorAP</title>
+ <title xml:lang="en" primary="true">KorAP</title>
+ <description xml:lang="de">Suche mit KorAP via SRU.</description>
+ <description xml:lang="en" primary="true">Search in KorAP via SRU.</description>
+ <author xml:lang="en">Institute for the German language</author>
+ <author xml:lang="de" primary="true">Institut für Deutsche Sprache</author>
+ </databaseInfo>
+
+ <indexInfo>
+ <set name="fcs" identifier="clarin.eu/fcs/1.0">
+ <title xml:lang="de">CLARIN Content Search</title>
+ <title xml:lang="en" primary="true">CLARIN Content Search</title>
+ </set>
+ <index search="true" scan="false" sort="false">
+ <title xml:lang="en" primary="true">Words</title>
+ <map primary="true">
+ <name set="fcs">words</name>
+ </map>
+ </index>
+ </indexInfo>
+
+ <schemaInfo>
+ <schema identifier="http://clarin.eu/fcs/1.0" name="fcs"
+ sort="false" retrieve="true">
+ <title xml:lang="en" primary="true">CLARIN Content Search</title>
+ </schema>
+ </schemaInfo>
+
+</endpoint-config>
diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..5b3a74b
--- /dev/null
+++ b/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+ id="KorapSRU" version="2.5">
+ <display-name>KorapSRU</display-name>
+
+ <servlet>
+ <display-name>KorAP SRU/CQL Service (HTTP Interface)</display-name>
+ <servlet-name>KorapSRU</servlet-name>
+ <servlet-class>eu.clarin.sru.server.utils.SRUServerServlet</servlet-class>
+ <init-param>
+ <param-name>eu.clarin.sru.server.numberOfRecords</param-name>
+ <param-value>25</param-value>
+ </init-param>
+ <init-param>
+ <param-name>eu.clarin.sru.server.maximumRecords</param-name>
+ <param-value>50</param-value>
+ </init-param>
+ <init-param>
+ <param-name>eu.clarin.sru.server.transport</param-name>
+ <param-value>http</param-value>
+ </init-param>
+ <init-param>
+ <param-name>eu.clarin.sru.server.host</param-name>
+ <param-value>clarin.ids-mannheim.de</param-value>
+ </init-param>
+ <init-param>
+ <param-name>eu.clarin.sru.server.port</param-name>
+ <param-value>80</param-value>
+ </init-param>
+ <init-param>
+ <param-name>eu.clarin.sru.server.database</param-name>
+ <param-value>korapsru</param-value>
+ </init-param>
+ <init-param>
+ <param-name>eu.clarin.sru.server.allowOverrideMaximumRecords</param-name>
+ <param-value>false</param-value>
+ </init-param>
+ <init-param>
+ <param-name>eu.clarin.sru.server.allowOverrideIndentResponse</param-name>
+ <param-value>true</param-value>
+ </init-param>
+ <init-param>
+ <param-name>eu.clarin.sru.server.utils.sruServerSearchEngineClass</param-name>
+ <param-value>de.mannheim.ids.korap.sru.KorapSRU</param-value>
+ </init-param>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+ <servlet-mapping>
+ <servlet-name>KorapSRU</servlet-name>
+ <url-pattern>/*</url-pattern>
+ </servlet-mapping>
+
+ <servlet>
+ <servlet-name>ResourceService</servlet-name>
+ <jsp-file>/_redirect.jsp</jsp-file>
+ <init-param>
+ <param-name>korapWebUrl</param-name>
+ <param-value>http://korap.ids-mannheim.de/app/#!login</param-value>
+ </init-param>
+ </servlet>
+ <servlet-mapping>
+ <servlet-name>ResourceService</servlet-name>
+ <url-pattern>/redirect/*</url-pattern>
+ </servlet-mapping>
+
+</web-app>
diff --git a/src/main/webapp/_redirect.jsp b/src/main/webapp/_redirect.jsp
new file mode 100644
index 0000000..7be9748
--- /dev/null
+++ b/src/main/webapp/_redirect.jsp
@@ -0,0 +1,30 @@
+<%@ page contentType="text/html; charset=UTF-8"
+ pageEncoding="UTF-8" session="false"
+%><%
+ String id = request.getPathInfo();
+ if (id != null) {
+ id = id.substring(1);
+ }
+ if ((id == null) || id.isEmpty()) {
+ id = "[N/A]";
+ }
+ final String korapURL = config.getInitParameter("korapWebUrl");
+%><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+<head>
+ <title>KorAP SRU to KorAP bridge</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <meta http-equiv="refresh" content="30; URL=<%= korapURL %>" />
+</head>
+<body>
+<h1>This resource is only available within KorAP</h1>
+<p>
+ Sorry, but the resource <em><%= id %></em> is not directly accessible for
+ browsing or download. <br />
+ Please use
+ <a href="<%= korapURL %>">KorAP</a> for
+ further exploration or more advanced research in the IDS corpora.
+</p>
+</body>
+</html>
diff --git a/src/test/java/de/mannheim/ids/korap/test/KorapClientTest.java b/src/test/java/de/mannheim/ids/korap/test/KorapClientTest.java
new file mode 100644
index 0000000..845a288
--- /dev/null
+++ b/src/test/java/de/mannheim/ids/korap/test/KorapClientTest.java
@@ -0,0 +1,36 @@
+package de.mannheim.ids.korap.test;
+
+import org.apache.http.client.HttpResponseException;
+import org.junit.Test;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+import de.mannheim.ids.korap.sru.KorapClient;
+import de.mannheim.ids.korap.sru.KorapResult;
+
+
+public class KorapClientTest {
+
+ @Test
+ public void testKorapClient() throws Exception{
+ KorapClient c = new KorapClient(25,50);
+
+// prox Kuh
+ KorapResult result = c.query("Haus", "1.2", 1, 5, null);
+ //System.out.println(result.getMatches().size());
+
+ }
+
+ @Test
+ public void testResource() throws HttpResponseException, Exception {
+ KorapClient c = new KorapClient(25,50);
+ JsonNode resources = c.retrieveResources();
+
+ for (JsonNode r : resources){
+ System.out.println(r);
+ System.out.println(r.get("name"));
+ }
+
+ }
+
+}