Index: SRUClient/trunk/pom.xml
===================================================================
--- SRUClient/trunk/pom.xml	(revision 5439)
+++ SRUClient/trunk/pom.xml	(revision 5743)
@@ -34,5 +34,5 @@
             <groupId>org.apache.httpcomponents</groupId>
             <artifactId>httpclient</artifactId>
-            <version>4.2.5</version>
+            <version>4.3.5</version>
         </dependency>
 
Index: SRUClient/trunk/src/main/java/eu/clarin/sru/client/SRUSimpleClient.java
===================================================================
--- SRUClient/trunk/src/main/java/eu/clarin/sru/client/SRUSimpleClient.java	(revision 5439)
+++ SRUClient/trunk/src/main/java/eu/clarin/sru/client/SRUSimpleClient.java	(revision 5743)
@@ -32,14 +32,16 @@
 
 import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
 import org.apache.http.HttpStatus;
 import org.apache.http.StatusLine;
 import org.apache.http.client.ClientProtocolException;
-import org.apache.http.client.HttpClient;
+import org.apache.http.client.config.CookieSpecs;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.utils.HttpClientUtils;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.params.CoreProtocolPNames;
-import org.apache.http.util.EntityUtils;
+import org.apache.http.config.SocketConfig;
+import org.apache.http.impl.NoConnectionReuseStrategy;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -65,4 +67,5 @@
  */
 public class SRUSimpleClient {
+    private static final String USER_AGENT = "SRU-Client/1.0.0";
     /** default version the client will use, if not otherwise specified */
     public static final SRUVersion DEFAULT_SRU_VERSION = SRUVersion.VERSION_1_2;
@@ -81,5 +84,5 @@
     private final SRUVersion defaultVersion;
     private final Map<String, SRURecordDataParser> parsers;
-    private final HttpClient httpClient;
+    private final CloseableHttpClient httpClient;
     private final XmlStreamReaderProxy proxy = new XmlStreamReaderProxy();
     private final SRUExplainRecordDataParser explainRecordParser =
@@ -138,7 +141,10 @@
         this.defaultVersion = defaultVersion;
         this.parsers        = parsers;
-        this.httpClient     = new DefaultHttpClient();
-        this.httpClient.getParams().setParameter(CoreProtocolPNames.USER_AGENT,
-                    "eu.clarin.sru.client/0.0.1");
+
+        // create HTTP client
+        // FIXME: get timeout values from somewhere?
+        final int connectTimeout = 30 * 1000;
+        final int socketTimeout = 180 * 1000;
+        httpClient = createHttpClient(connectTimeout, socketTimeout);
     }
 
@@ -206,13 +212,13 @@
         // create URI and perform request
         final URI uri = request.makeURI(defaultVersion);
-        HttpResponse response = executeRequest(uri);
-        HttpEntity entity = response.getEntity();
-        if (entity == null) {
-            throw new SRUClientException("cannot get entity");
-        }
-
-        InputStream stream = null;
-        SRUXMLStreamReader reader = null;
+        CloseableHttpResponse response = executeRequest(uri);
+        InputStream stream             = null;
+        SRUXMLStreamReader reader      = null;
         try {
+            final HttpEntity entity = response.getEntity();
+            if (entity == null) {
+                throw new SRUClientException("cannot get entity");
+            }
+
             stream = entity.getContent();
 
@@ -257,5 +263,9 @@
 
             /* make sure to release allocated resources */
-            HttpClientUtils.closeQuietly(response);
+            try {
+                response.close();
+            } catch (IOException e) {
+                /* IGNORE */
+            }
         }
     }
@@ -292,13 +302,12 @@
         // create URI and perform request
         final URI uri = request.makeURI(defaultVersion);
-        HttpResponse response = executeRequest(uri);
-        HttpEntity entity = response.getEntity();
-        if (entity == null) {
-            throw new SRUClientException("cannot get entity");
-        }
-
-        InputStream stream = null;
-        SRUXMLStreamReader reader = null;
+        CloseableHttpResponse response = executeRequest(uri);
+        InputStream stream             = null;
+        SRUXMLStreamReader reader      = null;
         try {
+            final HttpEntity entity = response.getEntity();
+            if (entity == null) {
+                throw new SRUClientException("cannot get entity");
+            }
             stream = entity.getContent();
 
@@ -343,5 +352,9 @@
 
             /* make sure to release allocated resources */
-            HttpClientUtils.closeQuietly(response);
+            try {
+                response.close();
+            } catch (IOException e) {
+                /* IGNORE */
+            }
         }
     }
@@ -378,13 +391,13 @@
         // create URI and perform request
         final URI uri = request.makeURI(defaultVersion);
-        HttpResponse response = executeRequest(uri);
-        HttpEntity entity = response.getEntity();
-        if (entity == null) {
-            throw new SRUClientException("cannot get entity");
-        }
-
-        InputStream stream = null;
-        SRUXMLStreamReader reader = null;
+        CloseableHttpResponse response = executeRequest(uri);
+        InputStream stream             = null;
+        SRUXMLStreamReader reader      = null;
         try {
+            final HttpEntity entity = response.getEntity();
+            if (entity == null) {
+                throw new SRUClientException("cannot get entity");
+            }
+
             stream = entity.getContent();
 
@@ -429,17 +442,22 @@
 
             /* make sure to release allocated resources */
-            HttpClientUtils.closeQuietly(response);
-        }
-    }
-
-
-    private HttpResponse executeRequest(URI uri) throws SRUClientException {
-        HttpGet request = null;
-        HttpResponse response = null;
+            try {
+                response.close();
+            } catch (IOException e) {
+                /* IGNORE */
+            }
+        }
+    }
+
+
+    private CloseableHttpResponse executeRequest(URI uri)
+            throws SRUClientException {
+        CloseableHttpResponse response = null;
+        boolean forceClose             = true;
         try {
             logger.debug("submitting HTTP request: {}", uri.toString());
             try {
-                request = new HttpGet(uri);
-                response = httpClient.execute(request);
+                HttpGet request = new HttpGet(uri);
+                response        = httpClient.execute(request);
                 StatusLine status = response.getStatusLine();
                 if (status.getStatusCode() != HttpStatus.SC_OK) {
@@ -451,4 +469,5 @@
                     }
                 }
+                forceClose = false;
                 return response;
             } catch (ClientProtocolException e) {
@@ -471,16 +490,10 @@
              * we've used
              */
-            if (response != null) {
+            if (forceClose && (response != null)) {
                 try {
-                    EntityUtils.consume(response.getEntity());
+                    response.close();
                 } catch (IOException ex) {
                     /* IGNORE */
                 }
-
-                /* make sure to release allocated resources */
-                HttpClientUtils.closeQuietly(response);
-            }
-            if (request != null) {
-                request.abort();
             }
             throw e;
@@ -1357,8 +1370,42 @@
 
 
-    private SRUXMLStreamReader createReader(InputStream in, boolean wrap)
+    private static SRUXMLStreamReader createReader(InputStream in, boolean wrap)
             throws XMLStreamException {
         return new SRUXMLStreamReader(in, wrap);
     }
 
+
+    private static CloseableHttpClient createHttpClient(int connectTimeout,
+            int socketTimeout) {
+        final PoolingHttpClientConnectionManager manager =
+                new PoolingHttpClientConnectionManager();
+        manager.setDefaultMaxPerRoute(8);
+        manager.setMaxTotal(128);
+
+        final SocketConfig socketConfig = SocketConfig.custom()
+                .setSoReuseAddress(true)
+                .setSoLinger(0)
+                .build();
+
+        final RequestConfig requestConfig = RequestConfig.custom()
+                .setAuthenticationEnabled(false)
+                .setRedirectsEnabled(true)
+                .setMaxRedirects(4)
+                .setCircularRedirectsAllowed(false)
+                .setCookieSpec(CookieSpecs.IGNORE_COOKIES)
+                .setConnectTimeout(connectTimeout)
+                .setSocketTimeout(socketTimeout)
+                .setConnectionRequestTimeout(0) /* infinite */
+                .setStaleConnectionCheckEnabled(false)
+                .build();
+
+        return HttpClients.custom()
+                .setUserAgent(USER_AGENT)
+                .setConnectionManager(manager)
+                .setDefaultSocketConfig(socketConfig)
+                .setDefaultRequestConfig(requestConfig)
+                .setConnectionReuseStrategy(new NoConnectionReuseStrategy())
+                .build();
+    }
+
 } // class SRUSimpleClient
Index: SRUClient/trunk/src/main/java/eu/clarin/sru/client/XmlStreamReaderUtils.java
===================================================================
--- SRUClient/trunk/src/main/java/eu/clarin/sru/client/XmlStreamReaderUtils.java	(revision 5439)
+++ SRUClient/trunk/src/main/java/eu/clarin/sru/client/XmlStreamReaderUtils.java	(revision 5743)
@@ -247,4 +247,18 @@
 
 
+    public static boolean peekEnd(XMLStreamReader reader,
+            String namespaceURI, String localName)
+            throws XMLStreamException {
+        if (reader.isWhiteSpace()) {
+            consumeWhitespace(reader);
+        }
+        if (!reader.isEndElement()) {
+            return false;
+        }
+        return namespaceURI.equals(reader.getNamespaceURI()) &&
+                localName.equals(reader.getLocalName());
+    }
+
+
     public static void consumeStart(XMLStreamReader reader)
             throws XMLStreamException {
Index: SRUClient/trunk/src/main/java/eu/clarin/sru/client/fcs/AbstractClarinFCSRecordDataParser.java
===================================================================
--- SRUClient/trunk/src/main/java/eu/clarin/sru/client/fcs/AbstractClarinFCSRecordDataParser.java	(revision 5743)
+++ SRUClient/trunk/src/main/java/eu/clarin/sru/client/fcs/AbstractClarinFCSRecordDataParser.java	(revision 5743)
@@ -0,0 +1,194 @@
+/**
+ * This software is copyright (c) 2012-2014 by
+ *  - Institut fuer Deutsche Sprache (http://www.ids-mannheim.de)
+ * This is free software. You can redistribute it
+ * and/or modify it under the terms described in
+ * the GNU General Public License v3 of which you
+ * should have received a copy. Otherwise you can download
+ * it from
+ *
+ *   http://www.gnu.org/licenses/gpl-3.0.txt
+ *
+ * @copyright Institut fuer Deutsche Sprache (http://www.ids-mannheim.de)
+ *
+ * @license http://www.gnu.org/licenses/gpl-3.0.txt
+ *  GNU General Public License v3
+ */
+package eu.clarin.sru.client.fcs;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import eu.clarin.sru.client.SRUClientException;
+import eu.clarin.sru.client.SRURecordData;
+import eu.clarin.sru.client.SRURecordDataParser;
+import eu.clarin.sru.client.XmlStreamReaderUtils;
+
+abstract class AbstractClarinFCSRecordDataParser implements SRURecordDataParser {
+    protected static final Logger logger =
+            LoggerFactory.getLogger(AbstractClarinFCSRecordDataParser.class);
+    protected final List<DataViewParser> parsers;
+
+
+    /**
+     * Constructor.
+     *
+     * @param parsers
+     *            the list of data view parsers to be used by this record data
+     *            parser. This list should contain one
+     *            {@link DataViewParserGenericDOM} or
+     *            {@link DataViewParserGenericString} instance.
+     * @throws NullPointerException
+     *             if parsers is <code>null</code>
+     * @throws IllegalArgumentException
+     *             if parsers is empty or contains duplicate entries
+     */
+    protected AbstractClarinFCSRecordDataParser(List<DataViewParser> parsers) {
+        if (parsers == null) {
+            throw new NullPointerException("parsers == null");
+        }
+        if (parsers.isEmpty()) {
+            throw new IllegalArgumentException("parsers is empty");
+        }
+
+        ArrayList<DataViewParser> list = new ArrayList<DataViewParser>();
+        boolean foundGeneric = false;
+        for (DataViewParser parser : parsers) {
+            if ((parser instanceof DataViewParserGenericDOM) ||
+                    (parser instanceof DataViewParserGenericString)) {
+                if (foundGeneric) {
+                    throw new IllegalAccessError("parser list should contain " +
+                            "only one instance of DataViewParserGenericDOM " +
+                            "or DataViewParserGenericString");
+                }
+                foundGeneric = true;
+            }
+            if (list.contains(parser)) {
+                throw new IllegalArgumentException("parser list should not " +
+                        "contain douplicates: " + parser.getClass().getName());
+            }
+            list.add(parser);
+        }
+
+        if (!foundGeneric) {
+            logger.warn("No generic type data view parser found. You should " +
+                    "make sure that the parser list contains one " +
+                    "DataViewParserGenericDOM or DataViewParserGenericString " +
+                    "instance");
+        }
+
+        this.parsers = Collections.unmodifiableList(list);
+    }
+
+
+    protected SRURecordData parse(XMLStreamReader reader, String ns)
+            throws XMLStreamException, SRUClientException {
+        // Resource
+        XmlStreamReaderUtils.readStart(reader, ns, "Resource", true, true);
+        final String pid =
+                XmlStreamReaderUtils.readAttributeValue(reader, null, "pid");
+        final String ref =
+                XmlStreamReaderUtils.readAttributeValue(reader, null, "ref");
+        XmlStreamReaderUtils.consumeStart(reader);
+
+        // Resource/Resource (optional)
+        if (XmlStreamReaderUtils.readStart(reader, ns, "Resource", false)) {
+            logger.info("skipping nested <Resource> element");
+            XmlStreamReaderUtils.readEnd(reader, ns, "Resource", true);
+        }
+
+        // Resource/DataView
+        final List<DataView> dataviews = parseDataViews(reader, ns);
+
+        // Resource/ResourceFragment
+        final List<Resource.ResourceFragment> resourceFragments =
+                parseResourceFragments(reader, ns);
+
+        XmlStreamReaderUtils.readEnd(reader, ns, "Resource", true);
+
+        return new ClarinFCSRecordData(pid, ref, dataviews, resourceFragments);
+    }
+
+
+    private List<DataView> parseDataViews(XMLStreamReader reader, String ns)
+            throws XMLStreamException, SRUClientException {
+        List<DataView> dataviews = null;
+
+        while (XmlStreamReaderUtils.readStart(reader, ns, "DataView", false, true)) {
+            final String pid =
+                    XmlStreamReaderUtils.readAttributeValue(reader, null, "pid");
+            final String ref =
+                    XmlStreamReaderUtils.readAttributeValue(reader, null, "ref");
+            final String type =
+                    XmlStreamReaderUtils.readAttributeValue(reader, null, "type");
+            if ((type == null) || type.isEmpty()) {
+                throw new SRUClientException("element <DataView> needs a "
+                        + "non-empty 'type' attribute");
+            }
+
+            // consume start element and get rid of any whitespace
+            XmlStreamReaderUtils.consumeStart(reader);
+            XmlStreamReaderUtils.consumeWhitespace(reader);
+
+            logger.debug("processing <DataView> of type = {}", type);
+
+            DataViewParser selectedParser = null;
+            for (DataViewParser parser : parsers) {
+                if (parser.acceptType(type) &&
+                        ((selectedParser == null) ||
+                         (selectedParser.getPriority() < parser.getPriority()))) {
+                    selectedParser = parser;
+                }
+            }
+
+            DataView dataview = null;
+            if (selectedParser != null) {
+                dataview = selectedParser.parse(reader, type, pid, ref);
+            } else {
+                logger.warn("no parser found for <DataView> of type = {}", type);
+            }
+
+            XmlStreamReaderUtils.readEnd(reader, ns, "DataView", true);
+
+            if (dataview != null) {
+                if (dataviews == null) {
+                    dataviews = new LinkedList<DataView>();
+                }
+                dataviews.add(dataview);
+            } else {
+                logger.warn("skipped <DataView> of type = {}", type);
+            }
+        } // while
+        return dataviews;
+    }
+
+
+    private List<Resource.ResourceFragment> parseResourceFragments(
+            XMLStreamReader reader, String ns) throws XMLStreamException,
+            SRUClientException {
+        List<Resource.ResourceFragment> resourceFragments = null;
+        while (XmlStreamReaderUtils.readStart(reader, ns, "ResourceFragment", false, true)) {
+            logger.debug("found ResourceFragment");
+            String pid = XmlStreamReaderUtils.readAttributeValue(reader, null, "pid");
+            String ref = XmlStreamReaderUtils.readAttributeValue(reader, null, "ref");
+            XmlStreamReaderUtils.consumeStart(reader);
+            final List<DataView> dataviews = parseDataViews(reader, ns);
+            XmlStreamReaderUtils.readEnd(reader, ns, "ResourceFragment", true);
+
+            if (resourceFragments == null) {
+                resourceFragments = new LinkedList<Resource.ResourceFragment>();
+            }
+            resourceFragments.add(new Resource.ResourceFragment(pid, ref, dataviews));
+        } // while
+        return resourceFragments;
+    }
+
+} // class AbstractClarinFCSRecordDataParser
Index: SRUClient/trunk/src/main/java/eu/clarin/sru/client/fcs/ClarinFCSClientBuilder.java
===================================================================
--- SRUClient/trunk/src/main/java/eu/clarin/sru/client/fcs/ClarinFCSClientBuilder.java	(revision 5743)
+++ SRUClient/trunk/src/main/java/eu/clarin/sru/client/fcs/ClarinFCSClientBuilder.java	(revision 5743)
@@ -0,0 +1,165 @@
+package eu.clarin.sru.client.fcs;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import eu.clarin.sru.client.SRUClient;
+import eu.clarin.sru.client.SRUSimpleClient;
+import eu.clarin.sru.client.SRUThreadedClient;
+import eu.clarin.sru.client.SRUVersion;
+
+
+public class ClarinFCSClientBuilder {
+    private static final boolean DEFAULT_UNKNOWN_AS_DOM =
+            false;
+    private static final SRUVersion DEFAULT_SRU_VERSION =
+            SRUVersion.VERSION_1_2;
+    private List<DataViewParser> parsers = new ArrayList<DataViewParser>();
+    private SRUVersion defaultSruVersion = DEFAULT_SRU_VERSION;
+    private boolean unknownAsDom;
+    private boolean legacySupport = false;
+
+
+    /**
+     * Constructor.
+     */
+    public ClarinFCSClientBuilder(boolean unknownAsDom) {
+        this.unknownAsDom = unknownAsDom;
+    }
+
+
+    /**
+     * Constructor.
+     */
+    public ClarinFCSClientBuilder() {
+        this(DEFAULT_UNKNOWN_AS_DOM);
+    }
+
+
+    public ClarinFCSClientBuilder defaults() {
+        doRegisterDataViewParser(parsers, new DataViewParserHits());
+        return this;
+    }
+
+
+    public ClarinFCSClientBuilder unkownDataViewAsDOM() {
+        unknownAsDom = true;
+        return this;
+    }
+
+
+    public ClarinFCSClientBuilder unkownDataViewAsString() {
+        unknownAsDom = false;
+        return this;
+    }
+
+
+    public ClarinFCSClientBuilder registerDataViewParser(DataViewParser parser) {
+        if (parser == null) {
+            throw new NullPointerException("parser == null");
+        }
+        if ((parser instanceof DataViewParserGenericDOM) ||
+                (parser instanceof DataViewParserGenericString)) {
+            throw new IllegalArgumentException("parsers of type '" +
+                    parser.getClass().getName() +
+                    "' should not be added manually");
+        }
+
+        if (!doRegisterDataViewParser(parsers, parser)) {
+            throw new IllegalArgumentException("parser of type '" +
+                    parser.getClass().getName() + "' was already registered");
+        }
+        return this;
+    }
+
+
+    public ClarinFCSClientBuilder enableLegacySupport() {
+        legacySupport = true;
+        return this;
+    }
+
+
+    public ClarinFCSClientBuilder disableLegacySupport() {
+        legacySupport = false;
+        return this;
+    }
+
+
+    @SuppressWarnings("deprecation")
+    public SRUSimpleClient buildSimpleClient() {
+        final List<DataViewParser> p = finalizeDataViewParsers();
+
+        SRUSimpleClient client = new SRUSimpleClient(defaultSruVersion);
+        client.registerRecordParser(new ClarinFCSRecordDataParser(p));
+        if (legacySupport) {
+            client.registerRecordParser(new LegacyClarinFCSRecordDataParser(p));
+        }
+        return client;
+    }
+
+
+    @SuppressWarnings("deprecation")
+    public SRUClient buildClient() {
+        final List<DataViewParser> p = finalizeDataViewParsers();
+
+        SRUClient client = new SRUClient(defaultSruVersion);
+        client.registerRecordParser(new ClarinFCSRecordDataParser(p));
+        if (legacySupport) {
+            client.registerRecordParser(new LegacyClarinFCSRecordDataParser(p));
+        }
+        return client;
+    }
+
+
+    @SuppressWarnings("deprecation")
+    public SRUThreadedClient buildThreadedClient() {
+        final List<DataViewParser> p = finalizeDataViewParsers();
+
+        SRUThreadedClient client = new SRUThreadedClient(defaultSruVersion);
+        client.registerRecordParser(new ClarinFCSRecordDataParser(p));
+        if (legacySupport) {
+            client.registerRecordParser(new LegacyClarinFCSRecordDataParser(p));
+        }
+        return client;
+    }
+
+
+    private List<DataViewParser> finalizeDataViewParsers() {
+        final List<DataViewParser> result =
+                new ArrayList<DataViewParser>(parsers.size() +
+                        (legacySupport ? 2 : 1));
+        result.addAll(parsers);
+        if (unknownAsDom) {
+            result.add(new DataViewParserGenericDOM());
+        } else {
+            result.add(new DataViewParserGenericString());
+        }
+        if (legacySupport) {
+            result.add(new DataViewParserKWIC());
+        }
+
+        return result;
+    }
+
+
+    public static ClarinFCSClientBuilder create() {
+        return new ClarinFCSClientBuilder();
+    }
+
+
+    public static ClarinFCSClientBuilder create(boolean unknownAsDom) {
+        return new ClarinFCSClientBuilder(unknownAsDom);
+    }
+
+
+    private static boolean doRegisterDataViewParser(
+            List<DataViewParser> parsers, DataViewParser parser) {
+        if (parsers.contains(parser)) {
+            return false;
+        } else {
+            parsers.add(parser);
+            return true;
+        }
+    }
+
+} // class ClarinFCSClientBuilder
Index: SRUClient/trunk/src/main/java/eu/clarin/sru/client/fcs/ClarinFCSRecordData.java
===================================================================
--- SRUClient/trunk/src/main/java/eu/clarin/sru/client/fcs/ClarinFCSRecordData.java	(revision 5439)
+++ SRUClient/trunk/src/main/java/eu/clarin/sru/client/fcs/ClarinFCSRecordData.java	(revision 5743)
@@ -30,5 +30,14 @@
      * The record schema for CLARIN-FCS records.
      */
-    public static final String RECORD_SCHEMA = "http://clarin.eu/fcs/1.0";
+    public static final String RECORD_SCHEMA =
+            "http://clarin.eu/fcs/resource";
+    /**
+     * The legacy record schema for CLARIN-FCS records.
+     * 
+     * @deprecated Only use to talk to legacy clients
+     */
+    @Deprecated
+    public static final String LEGACY_RECORD_SCHEMA =
+            "http://clarin.eu/fcs/1.0";
     private final Resource resource;
 
@@ -54,5 +63,5 @@
     /**
      * Get the CLARIN-FCS record resource.
-     * 
+     *
      * @return a {@link Resource} object
      */
Index: SRUClient/trunk/src/main/java/eu/clarin/sru/client/fcs/ClarinFCSRecordDataParser.java
===================================================================
--- SRUClient/trunk/src/main/java/eu/clarin/sru/client/fcs/ClarinFCSRecordDataParser.java	(revision 5743)
+++ SRUClient/trunk/src/main/java/eu/clarin/sru/client/fcs/ClarinFCSRecordDataParser.java	(revision 5743)
@@ -0,0 +1,68 @@
+/**
+ * This software is copyright (c) 2012-2013 by
+ *  - Institut fuer Deutsche Sprache (http://www.ids-mannheim.de)
+ * This is free software. You can redistribute it
+ * and/or modify it under the terms described in
+ * the GNU General Public License v3 of which you
+ * should have received a copy. Otherwise you can download
+ * it from
+ *
+ *   http://www.gnu.org/licenses/gpl-3.0.txt
+ *
+ * @copyright Institut fuer Deutsche Sprache (http://www.ids-mannheim.de)
+ *
+ * @license http://www.gnu.org/licenses/gpl-3.0.txt
+ *  GNU General Public License v3
+ */
+package eu.clarin.sru.client.fcs;
+
+import java.util.List;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import eu.clarin.sru.client.SRUClientException;
+import eu.clarin.sru.client.SRURecordData;
+
+
+/**
+ * A record data parse to parse records conforming to CLARIN-FCS specification.
+ */
+public class ClarinFCSRecordDataParser extends
+        AbstractClarinFCSRecordDataParser {
+
+
+    /**
+     * Constructor.
+     *
+     * @param parsers
+     *            the list of data view parsers to be used by this record data
+     *            parser. This list should contain one
+     *            {@link DataViewParserGenericDOM} or
+     *            {@link DataViewParserGenericString} instance.
+     * @throws NullPointerException
+     *             if parsers is <code>null</code>
+     * @throws IllegalArgumentException
+     *             if parsers is empty or contains duplicate entries
+     */
+    public ClarinFCSRecordDataParser(List<DataViewParser> parsers) {
+        super(parsers);
+    }
+
+
+
+    @Override
+    public String getRecordSchema() {
+        return ClarinFCSRecordData.RECORD_SCHEMA;
+    }
+
+
+    @Override
+    public SRURecordData parse(XMLStreamReader reader)
+            throws XMLStreamException, SRUClientException {
+        logger.debug("parsing CLARIN-FCS record");
+
+        return parse(reader, ClarinFCSRecordData.RECORD_SCHEMA);
+    }
+
+} // class ClarinFCSRecordParser
Index: SRUClient/trunk/src/main/java/eu/clarin/sru/client/fcs/ClarinFCSRecordParser.java
===================================================================
--- SRUClient/trunk/src/main/java/eu/clarin/sru/client/fcs/ClarinFCSRecordParser.java	(revision 5439)
+++ 	(revision )
@@ -1,154 +1,0 @@
-/**
- * This software is copyright (c) 2012-2013 by
- *  - Institut fuer Deutsche Sprache (http://www.ids-mannheim.de)
- * This is free software. You can redistribute it
- * and/or modify it under the terms described in
- * the GNU General Public License v3 of which you
- * should have received a copy. Otherwise you can download
- * it from
- *
- *   http://www.gnu.org/licenses/gpl-3.0.txt
- *
- * @copyright Institut fuer Deutsche Sprache (http://www.ids-mannheim.de)
- *
- * @license http://www.gnu.org/licenses/gpl-3.0.txt
- *  GNU General Public License v3
- */
-package eu.clarin.sru.client.fcs;
-
-import java.util.LinkedList;
-import java.util.List;
-
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamReader;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import eu.clarin.sru.client.SRUClientException;
-import eu.clarin.sru.client.SRURecordData;
-import eu.clarin.sru.client.SRURecordDataParser;
-import eu.clarin.sru.client.XmlStreamReaderUtils;
-
-
-/**
- * A record parse to parse records conforming to CLARIN-FCS specification.
- */
-public class ClarinFCSRecordParser implements SRURecordDataParser {
-    private static final Logger logger =
-            LoggerFactory.getLogger(ClarinFCSRecordParser.class);
-    private static final String FCS_NS =
-            ClarinFCSRecordData.RECORD_SCHEMA;
-    // TODO: make this configurable
-    private final DataViewParser[] parsers = new DataViewParser[] {
-            new DataViewParserGenericDOM(),
-//            new DataViewParserGenericString(),
-            new DataViewParserKWIC()
-    };
-
-
-    @Override
-    public String getRecordSchema() {
-        return ClarinFCSRecordData.RECORD_SCHEMA;
-    }
-
-
-    @Override
-    public SRURecordData parse(XMLStreamReader reader)
-            throws XMLStreamException, SRUClientException {
-        logger.debug("parsing CLARIN-FCS record");
-
-        // Resource
-        XmlStreamReaderUtils.readStart(reader, FCS_NS, "Resource", true, true);
-        String pid = XmlStreamReaderUtils.readAttributeValue(reader, null, "pid");
-        String ref = XmlStreamReaderUtils.readAttributeValue(reader, null, "ref");
-        XmlStreamReaderUtils.consumeStart(reader);
-
-        // Resource/Resource (optional)
-        if (XmlStreamReaderUtils.readStart(reader, FCS_NS, "Resource", false)) {
-            logger.info("skipping nested <Resource> element");
-            XmlStreamReaderUtils.readEnd(reader, FCS_NS, "Resource", true);
-        }
-
-        // Resource/DataView
-        final List<DataView> dataviews = parseDataViews(reader);
-
-        // Resource/ResourceFragment
-        final List<Resource.ResourceFragment> resourceFragments =
-                parseResourceFragments(reader);
-
-        XmlStreamReaderUtils.readEnd(reader, FCS_NS, "Resource", true);
-
-        return new ClarinFCSRecordData(pid, ref, dataviews, resourceFragments);
-    }
-
-
-    private List<DataView> parseDataViews(XMLStreamReader reader)
-            throws XMLStreamException, SRUClientException {
-        List<DataView> dataviews = null;
-
-        while (XmlStreamReaderUtils.readStart(reader, FCS_NS, "DataView", false, true)) {
-            String pid = XmlStreamReaderUtils.readAttributeValue(reader, null, "pid");
-            String ref = XmlStreamReaderUtils.readAttributeValue(reader, null, "ref");
-            String type = XmlStreamReaderUtils.readAttributeValue(reader, null, "type");
-            if ((type == null) || type.isEmpty()) {
-                throw new SRUClientException("element <DataView> needs a "
-                        + "non-empty 'type' attribute");
-            }
-
-            // consume start element and get rid of any whitespace
-            XmlStreamReaderUtils.consumeStart(reader);
-            XmlStreamReaderUtils.consumeWhitespace(reader);
-
-            logger.debug("processing <DataView> of type = {}", type);
-
-            DataViewParser parser = null;
-            for (int i = 0; i < parsers.length; i++) {
-                if (parsers[i].acceptType(type) &&
-                        ((parser == null) ||
-                         (parser.getPriority() < parsers[i].getPriority()))) {
-                    parser = parsers[i];
-                }
-            }
-
-            DataView dataview = null;
-            if (parser != null) {
-                dataview = parser.parse(reader, type, pid, ref);
-            } else {
-                logger.warn("no parser found for <DataView> of type = {}", type);
-            }
-
-            XmlStreamReaderUtils.readEnd(reader, FCS_NS, "DataView", true);
-
-            if (dataview != null) {
-                if (dataviews == null) {
-                    dataviews = new LinkedList<DataView>();
-                }
-                dataviews.add(dataview);
-            } else {
-                logger.warn("skipped <DataView> of type = {}", type);
-            }
-        } // while
-        return dataviews;
-    }
-
-
-    private List<Resource.ResourceFragment> parseResourceFragments(
-            XMLStreamReader reader) throws XMLStreamException,
-            SRUClientException {
-        List<Resource.ResourceFragment> resourceFragments = null;
-        while (XmlStreamReaderUtils.readStart(reader, FCS_NS, "ResourceFragment", false, true)) {
-            logger.debug("found ResourceFragment");
-            String pid = XmlStreamReaderUtils.readAttributeValue(reader, null, "pid");
-            String ref = XmlStreamReaderUtils.readAttributeValue(reader, null, "ref");
-            XmlStreamReaderUtils.consumeStart(reader);
-            final List<DataView> dataviews = parseDataViews(reader);
-            XmlStreamReaderUtils.readEnd(reader, FCS_NS, "ResourceFragment", true);
-
-            if (resourceFragments == null) {
-                resourceFragments = new LinkedList<Resource.ResourceFragment>();
-            }
-            resourceFragments.add(new Resource.ResourceFragment(pid, ref, dataviews));
-        } // while
-        return resourceFragments;
-    }
-
-} // class ClarinFCSRecordParser
Index: SRUClient/trunk/src/main/java/eu/clarin/sru/client/fcs/DataViewHits.java
===================================================================
--- SRUClient/trunk/src/main/java/eu/clarin/sru/client/fcs/DataViewHits.java	(revision 5743)
+++ SRUClient/trunk/src/main/java/eu/clarin/sru/client/fcs/DataViewHits.java	(revision 5743)
@@ -0,0 +1,82 @@
+package eu.clarin.sru.client.fcs;
+
+public class DataViewHits extends DataView {
+    /**
+     * The MIME type for CLARIN-FCS KWIC data views.
+     */
+    public static final String TYPE = "application/x-clarin-fcs-hits+xml";
+    private final String text;
+    private final int[] offsets;
+    private final int max_offset;
+
+
+    /**
+     * Constructor.
+     *
+     * @param pid
+     *            a persistent identifier or <code>null</code>
+     * @param ref
+     *            a reference URI or <code>null</code>
+     * @param text
+     *            the textual content of the hits
+     * @param offsets
+     *            an array of (start, end) offset pairs that indicate the part
+     *            of the text, that is considered a hit
+     * @param offsets_idx
+     *            the largest index (= hit_count * 2) within the offsets array
+     *            plus one
+     * @throws NullPointerException
+     *             if any mandatory argument is <code>null</code>
+     * @throws IllegalArgumentException
+     *             if any argument is illegal
+     */
+    protected DataViewHits(String pid, String ref, String text,
+            int[] offsets, int offsets_idx) {
+        super(TYPE, pid, ref);
+        if (text == null) {
+            throw new NullPointerException("text == null");
+        }
+        if (text.isEmpty()) {
+            throw new IllegalArgumentException("text is empty");
+        }
+        this.text = text;
+        if (offsets == null) {
+            throw new NullPointerException("offsets == null");
+        }
+        this.offsets = offsets;
+        if (offsets_idx < 0) {
+            throw new IllegalArgumentException("offset_idx < 0");
+        }
+        if (offsets_idx > offsets.length) {
+            throw new IllegalArgumentException("offset_idx > offsets.length");
+        }
+        this.max_offset = (offsets_idx / 2);
+    }
+
+
+    public int getHitCount() {
+        return max_offset;
+    }
+
+
+    public String getText() {
+        return text;
+    }
+
+
+    public int[] getHitOffsets(int idx) {
+        if (idx < 0) {
+            throw new IllegalArgumentException("idx < 0");
+        }
+        if (idx < max_offset) {
+            int[] result = new int[2];
+            result[0] = offsets[(2 *idx)];
+            result[1] = offsets[(2 * idx) + 1];
+            return result;
+        } else {
+            throw new ArrayIndexOutOfBoundsException("idx > " +
+                    (max_offset - 1));
+        }
+    }
+
+} // class DataViewHits
Index: SRUClient/trunk/src/main/java/eu/clarin/sru/client/fcs/DataViewKWIC.java
===================================================================
--- SRUClient/trunk/src/main/java/eu/clarin/sru/client/fcs/DataViewKWIC.java	(revision 5439)
+++ 	(revision )
@@ -1,84 +1,0 @@
-/**
- * This software is copyright (c) 2012-2013 by
- *  - Institut fuer Deutsche Sprache (http://www.ids-mannheim.de)
- * This is free software. You can redistribute it
- * and/or modify it under the terms described in
- * the GNU General Public License v3 of which you
- * should have received a copy. Otherwise you can download
- * it from
- *
- *   http://www.gnu.org/licenses/gpl-3.0.txt
- *
- * @copyright Institut fuer Deutsche Sprache (http://www.ids-mannheim.de)
- *
- * @license http://www.gnu.org/licenses/gpl-3.0.txt
- *  GNU General Public License v3
- */
-package eu.clarin.sru.client.fcs;
-
-/**
- * A CLARIN-FCS KWIC DataView.
- */
-public final class DataViewKWIC extends DataView {
-    /**
-     * The MIME type for CLARIN-FCS KWIC data views.
-     */
-    public static final String TYPE = "application/x-clarin-fcs-kwic+xml";
-    private final String left;
-    private final String keyword;
-    private final String right;
-
-
-    /**
-     * Constructor.
-     *
-     * @param pid
-     *            a persistent identifier or <code>null</code>
-     * @param ref
-     *            a reference URI or <code>null</code>
-     * @param left
-     *            the left KWIC context
-     * @param keyword
-     *            the matched KWIC context
-     * @param right
-     *            the right KWIC context
-     */
-    DataViewKWIC(String pid, String ref, String left, String keyword,
-            String right) {
-        super(TYPE, pid, ref);
-        this.left    = (left    != null) ? left    : "";
-        this.keyword = (keyword != null) ? keyword : "";
-        this.right   = (right   != null) ? right   : "";
-    }
-
-
-    /**
-     * Get the left KWIC context.
-     *
-     * @return the left KWIC context
-     */
-    public String getLeft() {
-        return left;
-    }
-
-
-    /**
-     * Get the matched KWIC context.
-     *
-     * @return the matched KWIC context
-     */
-    public String getKeyword() {
-        return keyword;
-    }
-
-
-    /**
-     * Get the right KWIC context.
-     *
-     * @return the right KWIC context
-     */
-    public String getRight() {
-        return right;
-    }
-
-} // class DataViewKWIC
Index: SRUClient/trunk/src/main/java/eu/clarin/sru/client/fcs/DataViewParserHits.java
===================================================================
--- SRUClient/trunk/src/main/java/eu/clarin/sru/client/fcs/DataViewParserHits.java	(revision 5743)
+++ SRUClient/trunk/src/main/java/eu/clarin/sru/client/fcs/DataViewParserHits.java	(revision 5743)
@@ -0,0 +1,78 @@
+package eu.clarin.sru.client.fcs;
+
+import java.util.Arrays;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import eu.clarin.sru.client.SRUClientException;
+import eu.clarin.sru.client.XmlStreamReaderUtils;
+
+
+public final class DataViewParserHits implements DataViewParser {
+    private static final int OFFSET_CHUNK_SIZE = 8;
+    private static final String FCS_HITS_NS =
+            "http://clarin.eu/fcs/dataview/hits";
+    private static final Logger logger =
+            LoggerFactory.getLogger(DataViewParserHits.class);
+
+
+    @Override
+    public boolean acceptType(String type) {
+        return DataViewHits.TYPE.equals(type);
+    }
+
+
+    @Override
+    public int getPriority() {
+        return 1000;
+    }
+
+
+    @Override
+    public DataView parse(XMLStreamReader reader, String type, String pid,
+            String ref) throws XMLStreamException, SRUClientException {
+        int offsets[] = new int[OFFSET_CHUNK_SIZE];
+        int offsets_idx = 0;
+        StringBuilder buffer = new StringBuilder();
+        XmlStreamReaderUtils.readStart(reader, FCS_HITS_NS, "Result", true);
+
+        int idx = 0;
+        while (!XmlStreamReaderUtils.peekEnd(reader, FCS_HITS_NS, "Result")) {
+            if (buffer.length() > 0) {
+                if (!Character.isWhitespace(buffer.charAt(buffer.length() - 1))) {
+                    buffer.append(' ');
+                }
+                idx = buffer.length();
+            }
+
+            if (XmlStreamReaderUtils.readStart(reader, FCS_HITS_NS, "Hit", false)) {
+                String hit = XmlStreamReaderUtils.readString(reader, false);
+                XmlStreamReaderUtils.readEnd(reader, FCS_HITS_NS, "Hit");
+                if (hit.length() > 0) {
+                    buffer.append(hit);
+                    if (offsets_idx == offsets.length) {
+                        offsets = Arrays.copyOf(offsets, offsets.length + 8);
+                    }
+                    /*
+                     * add pair of offsets and simultaneously increase index
+                     */
+                    offsets[offsets_idx++] = idx;
+                    offsets[offsets_idx++] = idx + hit.length();
+                } else {
+                    logger.warn("skipping empty <Hit> element within <Result> element");
+                }
+            } else {
+                buffer.append(XmlStreamReaderUtils.readString(reader, false));
+            }
+        } // while
+        XmlStreamReaderUtils.readEnd(reader, FCS_HITS_NS, "Result");
+
+        final String text = buffer.toString();
+        return new DataViewHits(pid, ref, text, offsets, offsets_idx);
+    }
+
+} // class DataViewParserHits
Index: SRUClient/trunk/src/main/java/eu/clarin/sru/client/fcs/DataViewParserKWIC.java
===================================================================
--- SRUClient/trunk/src/main/java/eu/clarin/sru/client/fcs/DataViewParserKWIC.java	(revision 5439)
+++ SRUClient/trunk/src/main/java/eu/clarin/sru/client/fcs/DataViewParserKWIC.java	(revision 5743)
@@ -29,4 +29,6 @@
     private static final String FCS_KWIC_NS = "http://clarin.eu/fcs/1.0/kwic";
     private static final String KWIC_LEGACY_TYPE = "kwic";
+    private static final String KWIC_TYPE =
+            "application/x-clarin-fcs-kwic+xml";
     private static final Logger logger =
             LoggerFactory.getLogger(DataViewParserKWIC.class);
@@ -34,6 +36,5 @@
     @Override
     public boolean acceptType(String type) {
-        return DataViewKWIC.TYPE.equals(type) ||
-                KWIC_LEGACY_TYPE.equals(type);
+        return KWIC_TYPE.equals(type) || KWIC_LEGACY_TYPE.equals(type);
     }
 
@@ -47,5 +48,7 @@
             String ref) throws XMLStreamException, SRUClientException {
         if (KWIC_LEGACY_TYPE.equals(type)) {
-            logger.warn("type '" + KWIC_LEGACY_TYPE + "' is deprecteded for a KWIC <DataView>, please use '" + DataViewKWIC.TYPE + "' instead");
+            logger.warn("type '" + KWIC_LEGACY_TYPE + "' is deprecated " +
+                    "for a KWIC <DataView>, please use '" +
+                    KWIC_TYPE + "' instead");
         }
         String left = null;
@@ -67,5 +70,26 @@
         logger.debug("left='{}' keyword='{}', right='{}'",
                 left, keyword, right);
-        return new DataViewKWIC(pid, ref, left, keyword, right);
+
+        logger.warn("Upgraded deprecated KWIC dataview to HITS dataview. " +
+                "Please upgrade to the new CLARIN-FCS specification " +
+                "as soon as possible.");
+        final int[] offsets    = new int[3];
+        final StringBuilder sb = new StringBuilder();
+        if (left != null) {
+            sb.append(left);
+            if (!Character.isWhitespace(sb.charAt(sb.length() - 1))) {
+                sb.append(" ");
+            }
+        }
+        offsets[0] = sb.length();
+        sb.append(keyword);
+        offsets[1] = sb.length();
+        if (right != null) {
+            if (!Character.isWhitespace(sb.charAt(sb.length() - 1))) {
+                sb.append(" ");
+            }
+            sb.append(right);
+        }
+        return new DataViewHits(pid, ref, sb.toString(), offsets, 3);
     }
 
Index: SRUClient/trunk/src/main/java/eu/clarin/sru/client/fcs/LegacyClarinFCSRecordDataParser.java
===================================================================
--- SRUClient/trunk/src/main/java/eu/clarin/sru/client/fcs/LegacyClarinFCSRecordDataParser.java	(revision 5743)
+++ SRUClient/trunk/src/main/java/eu/clarin/sru/client/fcs/LegacyClarinFCSRecordDataParser.java	(revision 5743)
@@ -0,0 +1,55 @@
+package eu.clarin.sru.client.fcs;
+
+import java.util.List;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import eu.clarin.sru.client.SRUClientException;
+import eu.clarin.sru.client.SRURecordData;
+
+
+/**
+ * A record data parse to parse legacy records.
+ *
+ * @deprecated Use only to talk to legacy clients
+ */
+@Deprecated
+public class LegacyClarinFCSRecordDataParser extends
+        AbstractClarinFCSRecordDataParser {
+
+    
+    /**
+     * Constructor.
+     *
+     * @param parsers
+     *            the list of data view parsers to be used by this record data
+     *            parser. This list should contain one
+     *            {@link DataViewParserGenericDOM} or
+     *            {@link DataViewParserGenericString} instance.
+     * @throws NullPointerException
+     *             if parsers is <code>null</code>
+     * @throws IllegalArgumentException
+     *             if parsers is empty or contains duplicate entries
+     */
+    public LegacyClarinFCSRecordDataParser(List<DataViewParser> parsers) {
+        super(parsers);
+    }
+
+
+    @Override
+    public String getRecordSchema() {
+        return ClarinFCSRecordData.LEGACY_RECORD_SCHEMA;
+    }
+
+
+    @Override
+    public SRURecordData parse(XMLStreamReader reader)
+            throws XMLStreamException, SRUClientException {
+        logger.warn("The endpoint supplied data in the deprecated CLARIN-FCS " +
+            "record data format. Please upgrade to the new CLARIN-FCS " +
+                "specification as soon as possible.");
+        return parse(reader, ClarinFCSRecordData.LEGACY_RECORD_SCHEMA);
+    }
+
+} // class LegacyClarinFCSRecordDataParser
Index: SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestClient.java
===================================================================
--- SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestClient.java	(revision 5439)
+++ SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestClient.java	(revision 5743)
@@ -20,5 +20,5 @@
 import org.slf4j.LoggerFactory;
 
-import eu.clarin.sru.client.fcs.ClarinFCSRecordParser;
+import eu.clarin.sru.client.fcs.ClarinFCSClientBuilder;
 
 
@@ -31,8 +31,10 @@
         if (args.length > 0) {
             logger.info("initializing client ...");
-            SRUClient client = new SRUClient();
 
-            // register record data parsers
-            client.registerRecordParser(new ClarinFCSRecordParser());
+            SRUClient client = ClarinFCSClientBuilder.create()
+                    .defaults()
+                    .unkownDataViewAsString()
+                    .enableLegacySupport()
+                    .buildClient();
 
             // explain
Index: SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestSimpleClient.java
===================================================================
--- SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestSimpleClient.java	(revision 5439)
+++ SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestSimpleClient.java	(revision 5743)
@@ -22,6 +22,6 @@
 import org.slf4j.LoggerFactory;
 
+import eu.clarin.sru.client.fcs.ClarinFCSClientBuilder;
 import eu.clarin.sru.client.fcs.ClarinFCSRecordData;
-import eu.clarin.sru.client.fcs.ClarinFCSRecordParser;
 
 
@@ -33,8 +33,10 @@
         if (args.length > 0) {
             logger.info("initializing client ...");
-            SRUSimpleClient client = new SRUSimpleClient();
 
-            // register record data parsers
-            client.registerRecordParser(new ClarinFCSRecordParser());
+            SRUSimpleClient client = ClarinFCSClientBuilder
+                        .create()
+                        .defaults()
+                        .unkownDataViewAsString()
+                        .buildSimpleClient();
 
             /*
Index: SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestThreadedClient.java
===================================================================
--- SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestThreadedClient.java	(revision 5439)
+++ SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestThreadedClient.java	(revision 5743)
@@ -23,5 +23,5 @@
 import org.slf4j.LoggerFactory;
 
-import eu.clarin.sru.client.fcs.ClarinFCSRecordParser;
+import eu.clarin.sru.client.fcs.ClarinFCSClientBuilder;
 
 @Deprecated
@@ -33,8 +33,9 @@
         if (args.length > 0) {
             logger.info("initializing client ...");
-            SRUThreadedClient client = new SRUThreadedClient();
 
-            // register record data parsers
-            client.registerRecordParser(new ClarinFCSRecordParser());
+            SRUThreadedClient client = ClarinFCSClientBuilder
+                    .create()
+                    .defaults()
+                    .buildThreadedClient();
 
             try {
Index: SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestThreadedClientCallback.java
===================================================================
--- SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestThreadedClientCallback.java	(revision 5439)
+++ SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestThreadedClientCallback.java	(revision 5743)
@@ -22,5 +22,5 @@
 import org.slf4j.LoggerFactory;
 
-import eu.clarin.sru.client.fcs.ClarinFCSRecordParser;
+import eu.clarin.sru.client.fcs.ClarinFCSClientBuilder;
 
 
@@ -32,8 +32,9 @@
         if (args.length > 0) {
             logger.info("initializing client ...");
-            SRUThreadedClient client = new SRUThreadedClient();
 
-            // register record data parsers
-            client.registerRecordParser(new ClarinFCSRecordParser());
+            SRUThreadedClient client = ClarinFCSClientBuilder
+                    .create()
+                    .defaults()
+                    .buildThreadedClient();
 
             try {
Index: SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestUtils.java
===================================================================
--- SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestUtils.java	(revision 5439)
+++ SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestUtils.java	(revision 5743)
@@ -30,5 +30,5 @@
 import eu.clarin.sru.client.fcs.DataViewGenericDOM;
 import eu.clarin.sru.client.fcs.DataViewGenericString;
-import eu.clarin.sru.client.fcs.DataViewKWIC;
+import eu.clarin.sru.client.fcs.DataViewHits;
 import eu.clarin.sru.client.fcs.Resource;
 
@@ -60,5 +60,5 @@
         SRUSearchRetrieveRequest request = new SRUSearchRetrieveRequest(baseURI);
         request.setQuery(query);
-        request.setRecordSchema(ClarinFCSRecordData.RECORD_SCHEMA);
+//        request.setRecordSchema(ClarinFCSRecordData.LEGACY_RECORD_SCHEMA);
         request.setMaximumRecords(5);
         request.setRecordPacking(SRURecordPacking.XML);
@@ -214,16 +214,36 @@
                 final DataViewGenericDOM view = (DataViewGenericDOM) dataview;
                 final Node root = view.getDocument().getFirstChild();
-                logger.info("{}DataView: root element <{}> / {}",
+                logger.info("{}DataView (generic dom): root element <{}> / {}",
                         s, root.getNodeName(),
                         root.getOwnerDocument().hashCode());
             } else if (dataview instanceof DataViewGenericString) {
-                final DataViewGenericString view = (DataViewGenericString) dataview;
-                logger.info("{}DataView: data = {}", s, view.getContent());
-            } else if (dataview.isMimeType(DataViewKWIC.TYPE)) {
-                final DataViewKWIC kw = (DataViewKWIC) dataview;
-                logger.info("{}DataView: {} / {} / {}",
-                        s, kw.getLeft(), kw.getKeyword(), kw.getRight());
-            }
-        }
+                final DataViewGenericString view =
+                        (DataViewGenericString) dataview;
+                logger.info("{}DataView (generic string): data = {}",
+                        s, view.getContent());
+            } else if (dataview instanceof DataViewHits) {
+                final DataViewHits hits = (DataViewHits) dataview;
+                logger.info("{}DataView: {}",
+                        s, addHitHighlights(hits));
+            } else {
+                logger.info("{}DataView: cannot display " +
+                        "contents of unexpected class '{}'",
+                        s, dataview.getClass().getName());
+            }
+        }
+    }
+
+
+    private static String addHitHighlights(DataViewHits hits) {
+        StringBuilder sb = new StringBuilder(hits.getText());
+        int corr = 0;
+        for (int i = 0; i < hits.getHitCount(); i++) {
+            int[] offsets = hits.getHitOffsets(i);
+            sb.insert(offsets[0] + corr, "[");
+            corr += 1;
+            sb.insert(offsets[1] + corr, "]");
+            corr += 1;
+        }
+        return sb.toString();
     }
 
