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"));
+		}
+
+	}
+	
+}