Index: SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestClient.java
===================================================================
--- SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestClient.java	(revision 6938)
+++ 	(revision )
@@ -1,94 +1,0 @@
-/**
- * This software is copyright (c) 2012-2016 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;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import eu.clarin.sru.client.fcs.ClarinFCSClientBuilder;
-import eu.clarin.sru.client.fcs.ClarinFCSEndpointDescriptionParser;
-
-
-public class TestClient {
-    private static final Logger logger =
-            LoggerFactory.getLogger(TestClient.class);
-
-
-    public static void main(String[] args) {
-        if (args.length > 0) {
-            logger.info("initializing client ...");
-
-            SRUClient client = new ClarinFCSClientBuilder()
-                    .addDefaultDataViewParsers()
-                    .setDefaultSRUVersion(SRUVersion.VERSION_2_0)
-                    .unknownDataViewAsString()
-                    .enableLegacySupport()
-                    .registerExtraResponseDataParser(
-                            new ClarinFCSEndpointDescriptionParser())
-                    .buildClient();
-
-            // explain
-            try {
-                logger.info("performing 'explain' request ...");
-                SRUExplainRequest request = TestUtils.makeExplainRequest(args[0]);
-                SRUExplainResponse response = client.explain(request);
-                TestUtils.printExplainResponse(response);
-            } catch (SRUClientException e) {
-                logger.error("a fatal error occured while performing 'explain' request", e);
-            }
-
-            // scan
-            try {
-                logger.info("performing 'scan' request ...");
-                SRUScanRequest request = TestUtils.makeScanRequest(args[0]);
-                SRUScanResponse response = client.scan(request);
-                TestUtils.printScanResponse(response);
-            } catch (SRUClientException e) {
-                logger.error("a fatal error occured while performing 'scan' request", e);
-            }
-
-            // searchRetrieve
-            try {
-                logger.info("performing 'searchRetrieve' request ...");
-                SRUSearchRetrieveRequest request = TestUtils.makeSearchRequest(args[0], null);
-                SRUSearchRetrieveResponse response = client.searchRetrieve(request);
-                TestUtils.printSearchResponse(response);
-            } catch (SRUClientException e) {
-                logger.error("a fatal error occured while performing 'searchRetrieve' request", e);
-            }
-
-            logger.info("done");
-        } else {
-            System.err.println("missing args");
-            System.exit(64);
-        }
-    }
-
-
-    static {
-        org.apache.log4j.BasicConfigurator
-                .configure(new org.apache.log4j.ConsoleAppender(
-                        new org.apache.log4j.PatternLayout("%-5p [%t] %m%n"),
-                        org.apache.log4j.ConsoleAppender.SYSTEM_ERR));
-        org.apache.log4j.Logger logger = org.apache.log4j.Logger
-                .getRootLogger();
-        logger.setLevel(org.apache.log4j.Level.INFO);
-        logger.getLoggerRepository().getLogger("eu.clarin")
-                .setLevel(org.apache.log4j.Level.DEBUG);
-    }
-
-}
Index: SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestSimpleClient.java
===================================================================
--- SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestSimpleClient.java	(revision 6938)
+++ 	(revision )
@@ -1,164 +1,0 @@
-/**
- * This software is copyright (c) 2012-2016 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;
-
-import java.util.List;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import eu.clarin.sru.client.fcs.ClarinFCSClientBuilder;
-import eu.clarin.sru.client.fcs.ClarinFCSRecordData;
-
-
-public class TestSimpleClient {
-    private static final Logger logger =
-            LoggerFactory.getLogger(TestSimpleClient.class);
-
-    public static void main(String[] args) {
-        if (args.length > 0) {
-            logger.info("initializing client ...");
-
-            SRUSimpleClient client = new ClarinFCSClientBuilder()
-                        .addDefaultDataViewParsers()
-                        .unknownDataViewAsString()
-                        .buildSimpleClient();
-
-            /*
-             * just use one dump handler for each request.
-             * A real application should be smarter here and use the
-             * appropriate handler
-             */
-            SRUDefaultHandlerAdapter handler = new SRUDefaultHandlerAdapter() {
-                @Override
-                public void onDiagnostics(List<SRUDiagnostic> diagnostics)
-                        throws SRUClientException {
-                    for (SRUDiagnostic diagnostic : diagnostics) {
-                        logger.info("onDiagnostics: uri={}, detail={}, message={}",
-                                diagnostic.getURI(), diagnostic.getDetails(),
-                                diagnostic.getMessage());
-                    }
-                }
-
-                @Override
-                public void onRequestStatistics(int bytes, long millisTotal,
-                        long millisNetwork, long millisParsing) {
-                    logger.info("onRequestStatistics(): {} bytes in {} millis",
-                            bytes, millisTotal);
-                }
-
-                @Override
-                public void onStartTerms() throws SRUClientException {
-                    logger.info("onStartTerms()");
-                }
-
-                @Override
-                public void onFinishTerms() throws SRUClientException {
-                    logger.info("onFinishTerms()");
-                }
-
-                @Override
-                public void onTerm(String value, int numberOfRecords,
-                        String displayTerm, SRUWhereInList whereInList)
-                        throws SRUClientException {
-                    logger.info("onTerm(): value = {}, numberOfRecords = {}, " +
-                            "displayTerm = {}, whereInList = {}",
-                            value, numberOfRecords, displayTerm, whereInList);
-                }
-
-                @Override
-                public void onStartRecords(int numberOfRecords,
-                        String resultSetId, int resultSetIdleTime)
-                        throws SRUClientException {
-                    logger.info("onStartRecords(): numberOfRecords = {}",
-                            numberOfRecords);
-                }
-
-                @Override
-                public void onFinishRecords(int nextRecordPosition)
-                        throws SRUClientException {
-                    logger.info("onFinishRecords(): nextRecordPosition = {}",
-                            nextRecordPosition);
-                }
-
-                @Override
-                public void onRecord(String identifier, int position,
-                        SRURecordData data) throws SRUClientException {
-                    logger.info("onRecord(): identifier = {}, position = {}, schema = {}",
-                                identifier, position, data.getRecordSchema());
-                    if (ClarinFCSRecordData.RECORD_SCHEMA.equals(data.getRecordSchema())) {
-                        ClarinFCSRecordData record =
-                                (ClarinFCSRecordData) data;
-                        TestUtils.dumpResource(record.getResource());
-                    } else if (SRUExplainRecordData.RECORD_SCHEMA.equals(data.getRecordSchema())) {
-                        TestUtils.dumpExplainRecordData(data);
-                    }
-                }
-
-                @Override
-                public void onSurrogateRecord(String identifier, int position,
-                        SRUDiagnostic data) throws SRUClientException {
-                    logger.info("onSurrogateRecord: identifier = {}, position = {}, uri={}, detail={}, message={}",
-                            identifier, position, data.getURI(), data.getDetails(), data.getMessage());
-                }
-            };
-
-            try {
-                logger.info("performing 'explain' request ...");
-                SRUExplainRequest request = TestUtils.makeExplainRequest(args[0]);
-                client.explain(request, handler);
-            } catch (SRUClientException e) {
-                logger.error("a fatal error occured while performing 'explain' request", e);
-            }
-
-            try {
-                logger.info("performing 'scan' request ...");
-                SRUScanRequest request = TestUtils.makeScanRequest(args[0]);
-                client.scan(request, handler);
-            } catch (SRUClientException e) {
-                logger.error("a fatal error occured while performing 'scan' request", e);
-            }
-
-            try {
-                logger.info("performing 'searchRetrieve' request ...");
-                SRUSearchRetrieveRequest request = TestUtils.makeSearchRequest(args[0], null);
-                client.searchRetrieve(request, handler);
-            } catch (SRUClientException e) {
-                logger.error("a fatal error occured while performing 'searchRetrieve' request", e);
-            }
-
-            logger.info("done");
-        } else {
-            System.err.println("missing args");
-            System.exit(64);
-        }
-    }
-
-
-    static {
-        org.apache.log4j.BasicConfigurator.configure(
-                new org.apache.log4j.ConsoleAppender(
-                        new org.apache.log4j.PatternLayout("%-5p [%t] %m%n"),
-                        org.apache.log4j.ConsoleAppender.SYSTEM_ERR));
-        org.apache.log4j.Logger logger =
-                org.apache.log4j.Logger.getRootLogger();
-        logger.setLevel(org.apache.log4j.Level.INFO);
-        logger.getLoggerRepository().getLogger("eu.clarin").setLevel(
-                org.apache.log4j.Level.DEBUG);
-    }
-
-} // class TestSimpleClient
Index: SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestThreadedClient.java
===================================================================
--- SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestThreadedClient.java	(revision 6938)
+++ 	(revision )
@@ -1,119 +1,0 @@
-/**
- * This software is copyright (c) 2012-2016 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;
-
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import eu.clarin.sru.client.fcs.ClarinFCSClientBuilder;
-import eu.clarin.sru.client.fcs.ClarinFCSEndpointDescriptionParser;
-
-@Deprecated
-public class TestThreadedClient {
-    private static final Logger logger =
-            LoggerFactory.getLogger(TestThreadedClient.class);
-
-    public static void main(String[] args) {
-        if (args.length > 0) {
-            logger.info("initializing client ...");
-
-            SRUThreadedClient client = new ClarinFCSClientBuilder()
-                    .addDefaultDataViewParsers()
-                    .unknownDataViewAsString()
-                    .enableLegacySupport()
-                    .registerExtraResponseDataParser(
-                            new ClarinFCSEndpointDescriptionParser())
-                    .buildThreadedClient();
-
-            try {
-                /*
-                 * the following requests will be run asynchronously and
-                 * concurrently
-                 */
-                logger.info("submitting 'explain' request ...");
-                SRUExplainRequest request1 = TestUtils.makeExplainRequest(args[0]);
-                Future<SRUExplainResponse> result1 = client.explain(request1);
-
-                logger.info("submitting 'scan' request ...");
-                SRUScanRequest request2 = TestUtils.makeScanRequest(args[0]);
-                Future<SRUScanResponse> result2 = client.scan(request2);
-
-                logger.info("submitting 'searchRetrieve' request ...");
-                SRUSearchRetrieveRequest request3 = TestUtils.makeSearchRequest(args[0], null);
-                Future<SRUSearchRetrieveResponse> result3 =
-                        client.searchRetrieve(request3);
-
-                /*
-                 * HACK: the following code is quick and dirty. Don't every busy
-                 * wait on responses like this in a real-world application!
-                 */
-                while (!(result1.isDone() && result2.isDone() &&
-                        result3.isDone())) {
-                    logger.debug("waiting for results ...");
-                    try {
-                        Thread.sleep(125);
-                    } catch (InterruptedException e) {
-                        /* IGNORE */
-                    }
-                }
-
-                try {
-                    TestUtils.printExplainResponse(result1.get());
-                } catch (ExecutionException e) {
-                    logger.error("some error occured while performing 'explain' request", e);
-                }
-                try {
-                    TestUtils.printScanResponse(result2.get());
-                } catch (ExecutionException e) {
-                    logger.error("some error occured while performing 'scan' request", e);
-                }
-                try {
-                    TestUtils.printSearchResponse(result3.get());
-                } catch (ExecutionException e) {
-                    logger.error("some error occured while performing 'searchRetrieve' request", e);
-                }
-            } catch (Exception e) {
-                logger.error("a fatal error occured while performing request", e);
-            }
-
-            client.shutdown();
-            logger.info("done");
-        } else {
-            System.err.println("missing args");
-            System.exit(64);
-        }
-    }
-
-
-
-
-    static {
-        org.apache.log4j.BasicConfigurator.configure(
-                new org.apache.log4j.ConsoleAppender(
-                        new org.apache.log4j.PatternLayout("%-5p [%t] %m%n"),
-                        org.apache.log4j.ConsoleAppender.SYSTEM_ERR));
-        org.apache.log4j.Logger logger =
-                org.apache.log4j.Logger.getRootLogger();
-        logger.setLevel(org.apache.log4j.Level.INFO);
-        logger.getLoggerRepository().getLogger("eu.clarin").setLevel(
-                org.apache.log4j.Level.DEBUG);
-    }
-
-}
Index: SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestThreadedClientCallback.java
===================================================================
--- SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestThreadedClientCallback.java	(revision 6938)
+++ 	(revision )
@@ -1,135 +1,0 @@
-/**
- * This software is copyright (c) 2012-2016 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;
-
-import java.util.concurrent.CountDownLatch;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import eu.clarin.sru.client.fcs.ClarinFCSClientBuilder;
-import eu.clarin.sru.client.fcs.ClarinFCSEndpointDescriptionParser;
-
-
-public class TestThreadedClientCallback {
-    private static final Logger logger =
-            LoggerFactory.getLogger(TestThreadedClientCallback.class);
-
-    public static void main(String[] args) {
-        if (args.length > 0) {
-            logger.info("initializing client ...");
-
-            SRUThreadedClient client = new ClarinFCSClientBuilder()
-                    .addDefaultDataViewParsers()
-                    .unknownDataViewAsString()
-                    .enableLegacySupport()
-                    .registerExtraResponseDataParser(
-                            new ClarinFCSEndpointDescriptionParser())
-                    .buildThreadedClient();
-
-            try {
-                final CountDownLatch latch = new CountDownLatch(3);
-
-                /*
-                 * the following requests will be run asynchronously and
-                 * concurrently
-                 * Invoke requests and supply a callback, that
-                 *  a) prints the results
-                 *  b) downs a latch (which is used to make the main-thread wait
-                 *     on the requests to be completed)
-                 */
-                logger.info("submitting 'explain' request ...");
-                SRUExplainRequest request1 =
-                        TestUtils.makeExplainRequest(args[0]);
-                client.explain(request1, new SRUCallback<SRUExplainRequest, SRUExplainResponse>() {
-                    @Override
-                    public void onSuccess(SRUExplainResponse response) {
-                        TestUtils.printExplainResponse(response);
-                        latch.countDown();
-                    }
-
-                    @Override
-                    public void onError(SRUExplainRequest request,
-                            SRUClientException error) {
-                        logger.error("error while performing request", error);
-                        latch.countDown();
-                    }
-                });
-
-                logger.info("submitting 'scan' request ...");
-                SRUScanRequest request2 =
-                        TestUtils.makeScanRequest(args[0]);
-                client.scan(request2, new SRUCallback<SRUScanRequest, SRUScanResponse>() {
-                    @Override
-                    public void onSuccess(SRUScanResponse response) {
-                        TestUtils.printScanResponse(response);
-                        latch.countDown();
-                    }
-
-                    @Override
-                    public void onError(SRUScanRequest request,
-                            SRUClientException error) {
-                        logger.error("error while performing request", error);
-                        latch.countDown();
-                    }
-                });
-
-                logger.info("submitting 'searchRetrieve' request ...");
-                SRUSearchRetrieveRequest request3 =
-                        TestUtils.makeSearchRequest(args[0], null);
-                client.searchRetrieve(request3, new SRUCallback<SRUSearchRetrieveRequest, SRUSearchRetrieveResponse>() {
-                    @Override
-                    public void onSuccess(SRUSearchRetrieveResponse response) {
-                        TestUtils.printSearchResponse(response);
-                        latch.countDown();
-                    }
-
-                    @Override
-                    public void onError(SRUSearchRetrieveRequest request,
-                            SRUClientException error) {
-                        logger.error("error while performing request", error);
-                        latch.countDown();
-                    }
-                });
-
-                latch.await();
-            } catch (Exception e) {
-                logger.error("a fatal error occured while performing request", e);
-            }
-
-            client.shutdown();
-            logger.info("done");
-        } else {
-            System.err.println("missing args");
-            System.exit(64);
-        }
-    }
-
-
-    static {
-        org.apache.log4j.BasicConfigurator.configure(
-                new org.apache.log4j.ConsoleAppender(
-                        new org.apache.log4j.PatternLayout("%-5p [%t] %m%n"),
-                        org.apache.log4j.ConsoleAppender.SYSTEM_ERR));
-        org.apache.log4j.Logger logger =
-                org.apache.log4j.Logger.getRootLogger();
-        logger.setLevel(org.apache.log4j.Level.INFO);
-        logger.getLoggerRepository().getLogger("eu.clarin").setLevel(
-                org.apache.log4j.Level.DEBUG);
-    }
-
-}
Index: SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestUtils.java
===================================================================
--- SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestUtils.java	(revision 6938)
+++ 	(revision )
@@ -1,345 +1,0 @@
-/**
- * This software is copyright (c) 2012-2016 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;
-
-import java.net.URI;
-import java.util.List;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.w3c.dom.Node;
-
-import eu.clarin.sru.client.SRUExplainRecordData.ConfigInfo;
-import eu.clarin.sru.client.SRUExplainRecordData.Schema;
-import eu.clarin.sru.client.fcs.ClarinFCSEndpointDescription;
-import eu.clarin.sru.client.fcs.ClarinFCSEndpointDescription.ResourceInfo;
-import eu.clarin.sru.client.fcs.ClarinFCSRecordData;
-import eu.clarin.sru.client.fcs.DataView;
-import eu.clarin.sru.client.fcs.DataViewAdvanced;
-import eu.clarin.sru.client.fcs.DataViewGenericDOM;
-import eu.clarin.sru.client.fcs.DataViewGenericString;
-import eu.clarin.sru.client.fcs.DataViewHits;
-import eu.clarin.sru.client.fcs.Resource;
-
-class TestUtils {
-    private static final Logger logger =
-            LoggerFactory.getLogger(TestUtils.class);
-
-    public static SRUExplainRequest makeExplainRequest(String baseURI) {
-        SRUExplainRequest request = new SRUExplainRequest(baseURI);
-        request.setExtraRequestData("x-indent-response", "4");
-        request.setExtraRequestData("x-fcs-endpoint-description", "true");
-        request.setParseRecordDataEnabled(true);
-        return request;
-    }
-
-
-    public static SRUScanRequest makeScanRequest(String baseURI) {
-        SRUScanRequest request = new SRUScanRequest(baseURI);
-        request.setScanClause("fcs.resource = root");
-        request.setExtraRequestData("x-clarin-resource-info", "true");
-        request.setExtraRequestData("x-indent-response", "4");
-        return request;
-    }
-
-
-    public static SRUSearchRetrieveRequest makeSearchRequest(String baseURI, String query) {
-        if ((query == null) || query.isEmpty()) {
-            query = "'Faustus'";
-        }
-        SRUSearchRetrieveRequest request = new SRUSearchRetrieveRequest(baseURI);
-        request.setQuery("fcs" /*SRUClientConstants.QUERY_TYPE_CQL*/, query);
-//        request.setRecordSchema(ClarinFCSRecordData.LEGACY_RECORD_SCHEMA);
-        request.setMaximumRecords(5);
-        request.setRecordXmlEscaping(SRURecordXmlEscaping.XML);
-        request.setRecordPacking(SRURecordPacking.PACKED);
-        request.setExtraRequestData("x-indent-response", "4");
-        return request;
-    }
-
-
-    public static void printExplainResponse(SRUExplainResponse response) {
-        logger.info("displaying results of 'explain' request ...");
-        if (response.hasDiagnostics()) {
-            for (SRUDiagnostic diagnostic : response.getDiagnostics()) {
-                logger.info("uri={}, message={}, detail={}",
-                        diagnostic.getURI(),
-                        diagnostic.getMessage(),
-                        diagnostic.getDetails());
-            }
-        }
-        if (response.hasRecord()) {
-            SRURecord record = response.getRecord();
-            logger.info("schema = {}", record.getRecordSchema());
-            if (record.isRecordSchema(SRUExplainRecordData.RECORD_SCHEMA)) {
-                dumpExplainRecordData(record.getRecordData());
-            }
-            if (record.hasExtraRecordData()) {
-                logger.info("extraRecordInfo = {}",
-                        record.getExtraRecordData());
-            }
-        }
-        if (response.hasExtraResponseData()) {
-            for (SRUExtraResponseData data : response.getExtraResponseData()) {
-                if (data instanceof ClarinFCSEndpointDescription) {
-                    dumpEndpointDescription(
-                            (ClarinFCSEndpointDescription) data);
-                } else {
-                    logger.info("extraResponseData = {} (class={})",
-                            data.getRootElement(), data.getClass().getName());
-                }
-
-            }
-        }
-    }
-
-
-    public static void printScanResponse(SRUScanResponse response) {
-        logger.info("displaying results of 'scan' request ...");
-        if (response.hasDiagnostics()) {
-            for (SRUDiagnostic diagnostic : response.getDiagnostics()) {
-                logger.info("uri={}, message={}, detail={}",
-                        diagnostic.getURI(),
-                        diagnostic.getMessage(),
-                        diagnostic.getDetails());
-            }
-        }
-        if (response.hasTerms()) {
-            for (SRUTerm term : response.getTerms()) {
-                logger.info("value={}, numberOfRecords={}, displayTerm={}",
-                            term.getValue(),
-                            term.getNumberOfRecords(),
-                            term.getDisplayTerm());
-            }
-        } else {
-            logger.info("no terms");
-        }
-    }
-
-
-    public static void printSearchResponse(SRUSearchRetrieveResponse response) {
-        logger.info("displaying results of 'searchRetrieve' request ...");
-        logger.info("numberOfRecords = {}, nextResultPosition = {}",
-                response.getNumberOfRecords(),
-                response.getNextRecordPosition());
-        if (response.hasDiagnostics()) {
-            for (SRUDiagnostic diagnostic : response.getDiagnostics()) {
-                logger.info("uri={}, message={}, detail={}",
-                        diagnostic.getURI(),
-                        diagnostic.getMessage(),
-                        diagnostic.getDetails());
-            }
-        }
-        if (response.hasRecords()) {
-            for (SRURecord record : response.getRecords()) {
-                logger.info("schema = {}, identifier = {}, position = {}",
-                        record.getRecordSchema(),
-                        record.getRecordIdentifier(),
-                        record.getRecordPosition());
-                if (record.isRecordSchema(ClarinFCSRecordData.RECORD_SCHEMA)) {
-                    ClarinFCSRecordData rd =
-                            (ClarinFCSRecordData) record.getRecordData();
-                    dumpResource(rd.getResource());
-                } else if (record.isRecordSchema(SRUSurrogateRecordData.RECORD_SCHEMA)) {
-                    SRUSurrogateRecordData r =
-                            (SRUSurrogateRecordData) record.getRecordData();
-                    logger.info("SURROGATE DIAGNOSTIC: uri={}, message={}, detail={}",
-                                r.getURI(), r.getMessage(), r.getDetails());
-                } else {
-                    logger.info("UNSUPPORTED SCHEMA: {}",
-                            record.getRecordSchema());
-                }
-            }
-        } else {
-            logger.info("no results");
-        }
-    }
-
-
-    public static void dumpExplainRecordData(SRURecordData recordData) {
-        if (SRUExplainRecordData.RECORD_SCHEMA.equals(recordData.getRecordSchema())) {
-            SRUExplainRecordData data = (SRUExplainRecordData) recordData;
-            logger.info("host={}, port={}, database={}",
-                    data.getServerInfo().getHost(),
-                    data.getServerInfo().getPort(),
-                    data.getServerInfo().getDatabase());
-            List<Schema> schemaInfo = data.getSchemaInfo();
-            if (schemaInfo != null) {
-                for (Schema schema : schemaInfo) {
-                    logger.debug("schema: identifier={}, name={}, " +
-                            "location={}, sort={}, retrieve={}",
-                            schema.getIdentifier(),
-                            schema.getName(),
-                            schema.getLocation(),
-                            schema.getSort(),
-                            schema.getRetrieve());
-                }
-            }
-            ConfigInfo configInfo = data.getConfigInfo();
-            if (configInfo != null) {
-                if (configInfo.getDefaults() != null) {
-                    logger.debug("configInfo/default = {}",
-                            configInfo.getDefaults());
-                }
-                if (configInfo.getSettings() != null) {
-                    logger.debug("configInfo/setting = {}",
-                            configInfo.getSettings());
-                }
-                if (configInfo.getSupports() != null) {
-                    logger.debug("configInfo/supports = {}",
-                            configInfo.getSupports());
-                }
-            }
-        }
-    }
-
-
-    public static void dumpResource(Resource resource) {
-        logger.info("CLARIN-FCS: pid={}, ref={}",
-                resource.getPid(), resource.getRef());
-        if (resource.hasDataViews()) {
-            dumpDataView("CLARIN-FCS: ", resource.getDataViews());
-        }
-        if (resource.hasResourceFragments()) {
-            for (Resource.ResourceFragment fragment : resource.getResourceFragments()) {
-                logger.debug("CLARIN-FCS: ResourceFragment: pid={}, ref={}",
-                        fragment.getPid(), fragment.getRef());
-                if (fragment.hasDataViews()) {
-                    dumpDataView("CLARIN-FCS: ResourceFragment/", fragment.getDataViews());
-                }
-            }
-        }
-    }
-
-
-    private static void dumpEndpointDescription(ClarinFCSEndpointDescription ed) {
-        logger.info("dumping <EndpointDescription> (version={})",
-                ed.getVersion());
-        for (URI capability : ed.getCapabilities()) {
-            logger.info("  capability: {}", capability);
-        } // for
-        for (ClarinFCSEndpointDescription.DataView dataView :
-            ed.getSupportedDataViews()) {
-            logger.info("  supportedDataView: id={}, type={}, policy={}",
-                    dataView.getIdentifier(),
-                    dataView.getMimeType(),
-                    dataView.getDeliveryPolicy());
-        } // for
-        for (ClarinFCSEndpointDescription.Layer layer :
-            ed.getSupportedLayers()) {
-            logger.info("  supportedLayer: id={}, result-id={}, " +
-                    "layer-type={}, encoding={}, qualifier={}, " +
-                    "alt-value-info={}, alt-value-info-uri={}",
-                    layer.getIdentifier(),
-                    layer.getResultId(),
-                    layer.getLayerType(),
-                    layer.getEncoding(),
-                    layer.getQualifier(),
-                    layer.getAltValueInfo(),
-                    layer.getAltValueInfoURI());
-        }
-        dumpResourceInfo(ed.getResources(), 1, "  ");
-    }
-
-
-    private static void dumpResourceInfo(List<ResourceInfo> ris, int depth,
-            String indent) {
-        for (ResourceInfo ri : ris) {
-            logger.info("{}[depth={}] <ResourceInfo>", indent, depth);
-            logger.info("{}    pid={}", indent, ri.getPid());
-            logger.info("{}    title: {}", indent, ri.getTitle());
-            if (ri.getDescription() != null) {
-                logger.info("{}    description: {}",
-                        indent, ri.getDescription());
-            }
-            if (ri.getLandingPageURI() != null) {
-                logger.info("{}    landingPageURI: {}",
-                        indent, ri.getLandingPageURI());
-            }
-            for (ClarinFCSEndpointDescription.DataView dv :
-                ri.getAvailableDataViews()) {
-                logger.info("{}    available dataviews: type={}, policy={}",
-                        indent, dv.getMimeType(), dv.getDeliveryPolicy());
-            }
-            for (ClarinFCSEndpointDescription.Layer l :
-                ri.getAvailableLayers()) {
-                logger.info("{}    available layers: result-id={}, layer-type={}",
-                        indent, l.getResultId(), l.getLayerType());
-            }
-            if (ri.hasSubResources()) {
-                dumpResourceInfo(ri.getSubResources(),
-                        depth + 1, indent + "  ");
-            }
-        }
-    }
-
-
-    private static void dumpDataView(String s, List<DataView> dataviews) {
-        for (DataView dataview : dataviews) {
-            logger.info("{}DataView: type={}, pid={}, ref={}",
-                    s, dataview.getMimeType(), dataview.getPid(),
-                    dataview.getRef());
-            if (dataview instanceof DataViewGenericDOM) {
-                final DataViewGenericDOM view = (DataViewGenericDOM) dataview;
-                final Node root = view.getDocument().getFirstChild();
-                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 (generic string): data = {}",
-                        s, view.getContent());
-            } else if (dataview instanceof DataViewHits) {
-                final DataViewHits hits = (DataViewHits) dataview;
-                logger.info("{}DataView: {}",
-                        s, addHitHighlights(hits));
-            } else if (dataview instanceof DataViewAdvanced) {
-                final DataViewAdvanced adv = (DataViewAdvanced) dataview;
-                logger.info("{}DataView: unit={}",
-                        s, adv.getUnit());
-                for (DataViewAdvanced.Layer layer : adv.getLayers()) {
-                    logger.info("{}DataView: Layer: id={}",
-                            s, layer.getId());
-                    for (DataViewAdvanced.Span span : layer.getSpans()) {
-                        logger.info("{}DataView:   Span: start={}, end={}, content={}",
-                                s, span.getStartOffset(), span.getEndOffset(), span.getContent());
-                    }
-                }
-            } 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();
-    }
-
-} // class TestUtils
Index: SRUClient/trunk/src/test/java/eu/clarin/sru/client/fcs/TestClient.java
===================================================================
--- SRUClient/trunk/src/test/java/eu/clarin/sru/client/fcs/TestClient.java	(revision 6942)
+++ SRUClient/trunk/src/test/java/eu/clarin/sru/client/fcs/TestClient.java	(revision 6942)
@@ -0,0 +1,103 @@
+/**
+ * This software is copyright (c) 2012-2016 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 org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import eu.clarin.sru.client.SRUClient;
+import eu.clarin.sru.client.SRUClientException;
+import eu.clarin.sru.client.SRUExplainRequest;
+import eu.clarin.sru.client.SRUExplainResponse;
+import eu.clarin.sru.client.SRUScanRequest;
+import eu.clarin.sru.client.SRUScanResponse;
+import eu.clarin.sru.client.SRUSearchRetrieveRequest;
+import eu.clarin.sru.client.SRUSearchRetrieveResponse;
+import eu.clarin.sru.client.SRUVersion;
+import eu.clarin.sru.client.fcs.ClarinFCSClientBuilder;
+import eu.clarin.sru.client.fcs.ClarinFCSEndpointDescriptionParser;
+
+
+public class TestClient {
+    private static final Logger logger =
+            LoggerFactory.getLogger(TestClient.class);
+
+
+    public static void main(String[] args) {
+        if (args.length > 0) {
+            logger.info("initializing client ...");
+
+            SRUClient client = new ClarinFCSClientBuilder()
+                    .addDefaultDataViewParsers()
+                    .setDefaultSRUVersion(SRUVersion.VERSION_2_0)
+                    .unknownDataViewAsString()
+                    .enableLegacySupport()
+                    .registerExtraResponseDataParser(
+                            new ClarinFCSEndpointDescriptionParser())
+                    .buildClient();
+
+            // explain
+            try {
+                logger.info("performing 'explain' request ...");
+                SRUExplainRequest request = TestUtils.makeExplainRequest(args[0]);
+                SRUExplainResponse response = client.explain(request);
+                TestUtils.printExplainResponse(response);
+            } catch (SRUClientException e) {
+                logger.error("a fatal error occured while performing 'explain' request", e);
+            }
+
+            // scan
+            try {
+                logger.info("performing 'scan' request ...");
+                SRUScanRequest request = TestUtils.makeScanRequest(args[0]);
+                SRUScanResponse response = client.scan(request);
+                TestUtils.printScanResponse(response);
+            } catch (SRUClientException e) {
+                logger.error("a fatal error occured while performing 'scan' request", e);
+            }
+
+            // searchRetrieve
+            try {
+                logger.info("performing 'searchRetrieve' request ...");
+                SRUSearchRetrieveRequest request = TestUtils.makeSearchRequest(args[0], null);
+                SRUSearchRetrieveResponse response = client.searchRetrieve(request);
+                TestUtils.printSearchResponse(response);
+            } catch (SRUClientException e) {
+                logger.error("a fatal error occured while performing 'searchRetrieve' request", e);
+            }
+
+            logger.info("done");
+        } else {
+            System.err.println("missing args");
+            System.exit(64);
+        }
+    }
+
+
+    static {
+        org.apache.log4j.BasicConfigurator
+                .configure(new org.apache.log4j.ConsoleAppender(
+                        new org.apache.log4j.PatternLayout("%-5p [%t] %m%n"),
+                        org.apache.log4j.ConsoleAppender.SYSTEM_ERR));
+        org.apache.log4j.Logger logger = org.apache.log4j.Logger
+                .getRootLogger();
+        logger.setLevel(org.apache.log4j.Level.INFO);
+        logger.getLoggerRepository().getLogger("eu.clarin")
+                .setLevel(org.apache.log4j.Level.DEBUG);
+    }
+
+}
Index: SRUClient/trunk/src/test/java/eu/clarin/sru/client/fcs/TestSimpleClient.java
===================================================================
--- SRUClient/trunk/src/test/java/eu/clarin/sru/client/fcs/TestSimpleClient.java	(revision 6942)
+++ SRUClient/trunk/src/test/java/eu/clarin/sru/client/fcs/TestSimpleClient.java	(revision 6942)
@@ -0,0 +1,174 @@
+/**
+ * This software is copyright (c) 2012-2016 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 org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import eu.clarin.sru.client.SRUClientException;
+import eu.clarin.sru.client.SRUDefaultHandlerAdapter;
+import eu.clarin.sru.client.SRUDiagnostic;
+import eu.clarin.sru.client.SRUExplainRecordData;
+import eu.clarin.sru.client.SRUExplainRequest;
+import eu.clarin.sru.client.SRURecordData;
+import eu.clarin.sru.client.SRUScanRequest;
+import eu.clarin.sru.client.SRUSearchRetrieveRequest;
+import eu.clarin.sru.client.SRUSimpleClient;
+import eu.clarin.sru.client.SRUWhereInList;
+import eu.clarin.sru.client.fcs.ClarinFCSClientBuilder;
+import eu.clarin.sru.client.fcs.ClarinFCSRecordData;
+
+
+public class TestSimpleClient {
+    private static final Logger logger =
+            LoggerFactory.getLogger(TestSimpleClient.class);
+
+    public static void main(String[] args) {
+        if (args.length > 0) {
+            logger.info("initializing client ...");
+
+            SRUSimpleClient client = new ClarinFCSClientBuilder()
+                        .addDefaultDataViewParsers()
+                        .unknownDataViewAsString()
+                        .buildSimpleClient();
+
+            /*
+             * just use one dump handler for each request.
+             * A real application should be smarter here and use the
+             * appropriate handler
+             */
+            SRUDefaultHandlerAdapter handler = new SRUDefaultHandlerAdapter() {
+                @Override
+                public void onDiagnostics(List<SRUDiagnostic> diagnostics)
+                        throws SRUClientException {
+                    for (SRUDiagnostic diagnostic : diagnostics) {
+                        logger.info("onDiagnostics: uri={}, detail={}, message={}",
+                                diagnostic.getURI(), diagnostic.getDetails(),
+                                diagnostic.getMessage());
+                    }
+                }
+
+                @Override
+                public void onRequestStatistics(int bytes, long millisTotal,
+                        long millisNetwork, long millisParsing) {
+                    logger.info("onRequestStatistics(): {} bytes in {} millis",
+                            bytes, millisTotal);
+                }
+
+                @Override
+                public void onStartTerms() throws SRUClientException {
+                    logger.info("onStartTerms()");
+                }
+
+                @Override
+                public void onFinishTerms() throws SRUClientException {
+                    logger.info("onFinishTerms()");
+                }
+
+                @Override
+                public void onTerm(String value, int numberOfRecords,
+                        String displayTerm, SRUWhereInList whereInList)
+                        throws SRUClientException {
+                    logger.info("onTerm(): value = {}, numberOfRecords = {}, " +
+                            "displayTerm = {}, whereInList = {}",
+                            value, numberOfRecords, displayTerm, whereInList);
+                }
+
+                @Override
+                public void onStartRecords(int numberOfRecords,
+                        String resultSetId, int resultSetIdleTime)
+                        throws SRUClientException {
+                    logger.info("onStartRecords(): numberOfRecords = {}",
+                            numberOfRecords);
+                }
+
+                @Override
+                public void onFinishRecords(int nextRecordPosition)
+                        throws SRUClientException {
+                    logger.info("onFinishRecords(): nextRecordPosition = {}",
+                            nextRecordPosition);
+                }
+
+                @Override
+                public void onRecord(String identifier, int position,
+                        SRURecordData data) throws SRUClientException {
+                    logger.info("onRecord(): identifier = {}, position = {}, schema = {}",
+                                identifier, position, data.getRecordSchema());
+                    if (ClarinFCSRecordData.RECORD_SCHEMA.equals(data.getRecordSchema())) {
+                        ClarinFCSRecordData record =
+                                (ClarinFCSRecordData) data;
+                        TestUtils.dumpResource(record.getResource());
+                    } else if (SRUExplainRecordData.RECORD_SCHEMA.equals(data.getRecordSchema())) {
+                        TestUtils.dumpExplainRecordData(data);
+                    }
+                }
+
+                @Override
+                public void onSurrogateRecord(String identifier, int position,
+                        SRUDiagnostic data) throws SRUClientException {
+                    logger.info("onSurrogateRecord: identifier = {}, position = {}, uri={}, detail={}, message={}",
+                            identifier, position, data.getURI(), data.getDetails(), data.getMessage());
+                }
+            };
+
+            try {
+                logger.info("performing 'explain' request ...");
+                SRUExplainRequest request = TestUtils.makeExplainRequest(args[0]);
+                client.explain(request, handler);
+            } catch (SRUClientException e) {
+                logger.error("a fatal error occured while performing 'explain' request", e);
+            }
+
+            try {
+                logger.info("performing 'scan' request ...");
+                SRUScanRequest request = TestUtils.makeScanRequest(args[0]);
+                client.scan(request, handler);
+            } catch (SRUClientException e) {
+                logger.error("a fatal error occured while performing 'scan' request", e);
+            }
+
+            try {
+                logger.info("performing 'searchRetrieve' request ...");
+                SRUSearchRetrieveRequest request = TestUtils.makeSearchRequest(args[0], null);
+                client.searchRetrieve(request, handler);
+            } catch (SRUClientException e) {
+                logger.error("a fatal error occured while performing 'searchRetrieve' request", e);
+            }
+
+            logger.info("done");
+        } else {
+            System.err.println("missing args");
+            System.exit(64);
+        }
+    }
+
+
+    static {
+        org.apache.log4j.BasicConfigurator.configure(
+                new org.apache.log4j.ConsoleAppender(
+                        new org.apache.log4j.PatternLayout("%-5p [%t] %m%n"),
+                        org.apache.log4j.ConsoleAppender.SYSTEM_ERR));
+        org.apache.log4j.Logger logger =
+                org.apache.log4j.Logger.getRootLogger();
+        logger.setLevel(org.apache.log4j.Level.INFO);
+        logger.getLoggerRepository().getLogger("eu.clarin").setLevel(
+                org.apache.log4j.Level.DEBUG);
+    }
+
+} // class TestSimpleClient
Index: SRUClient/trunk/src/test/java/eu/clarin/sru/client/fcs/TestThreadedClient.java
===================================================================
--- SRUClient/trunk/src/test/java/eu/clarin/sru/client/fcs/TestThreadedClient.java	(revision 6942)
+++ SRUClient/trunk/src/test/java/eu/clarin/sru/client/fcs/TestThreadedClient.java	(revision 6942)
@@ -0,0 +1,126 @@
+/**
+ * This software is copyright (c) 2012-2016 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.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import eu.clarin.sru.client.SRUExplainRequest;
+import eu.clarin.sru.client.SRUExplainResponse;
+import eu.clarin.sru.client.SRUScanRequest;
+import eu.clarin.sru.client.SRUScanResponse;
+import eu.clarin.sru.client.SRUSearchRetrieveRequest;
+import eu.clarin.sru.client.SRUSearchRetrieveResponse;
+import eu.clarin.sru.client.SRUThreadedClient;
+import eu.clarin.sru.client.fcs.ClarinFCSClientBuilder;
+import eu.clarin.sru.client.fcs.ClarinFCSEndpointDescriptionParser;
+
+@Deprecated
+public class TestThreadedClient {
+    private static final Logger logger =
+            LoggerFactory.getLogger(TestThreadedClient.class);
+
+    public static void main(String[] args) {
+        if (args.length > 0) {
+            logger.info("initializing client ...");
+
+            SRUThreadedClient client = new ClarinFCSClientBuilder()
+                    .addDefaultDataViewParsers()
+                    .unknownDataViewAsString()
+                    .enableLegacySupport()
+                    .registerExtraResponseDataParser(
+                            new ClarinFCSEndpointDescriptionParser())
+                    .buildThreadedClient();
+
+            try {
+                /*
+                 * the following requests will be run asynchronously and
+                 * concurrently
+                 */
+                logger.info("submitting 'explain' request ...");
+                SRUExplainRequest request1 = TestUtils.makeExplainRequest(args[0]);
+                Future<SRUExplainResponse> result1 = client.explain(request1);
+
+                logger.info("submitting 'scan' request ...");
+                SRUScanRequest request2 = TestUtils.makeScanRequest(args[0]);
+                Future<SRUScanResponse> result2 = client.scan(request2);
+
+                logger.info("submitting 'searchRetrieve' request ...");
+                SRUSearchRetrieveRequest request3 = TestUtils.makeSearchRequest(args[0], null);
+                Future<SRUSearchRetrieveResponse> result3 =
+                        client.searchRetrieve(request3);
+
+                /*
+                 * HACK: the following code is quick and dirty. Don't every busy
+                 * wait on responses like this in a real-world application!
+                 */
+                while (!(result1.isDone() && result2.isDone() &&
+                        result3.isDone())) {
+                    logger.debug("waiting for results ...");
+                    try {
+                        Thread.sleep(125);
+                    } catch (InterruptedException e) {
+                        /* IGNORE */
+                    }
+                }
+
+                try {
+                    TestUtils.printExplainResponse(result1.get());
+                } catch (ExecutionException e) {
+                    logger.error("some error occured while performing 'explain' request", e);
+                }
+                try {
+                    TestUtils.printScanResponse(result2.get());
+                } catch (ExecutionException e) {
+                    logger.error("some error occured while performing 'scan' request", e);
+                }
+                try {
+                    TestUtils.printSearchResponse(result3.get());
+                } catch (ExecutionException e) {
+                    logger.error("some error occured while performing 'searchRetrieve' request", e);
+                }
+            } catch (Exception e) {
+                logger.error("a fatal error occured while performing request", e);
+            }
+
+            client.shutdown();
+            logger.info("done");
+        } else {
+            System.err.println("missing args");
+            System.exit(64);
+        }
+    }
+
+
+
+
+    static {
+        org.apache.log4j.BasicConfigurator.configure(
+                new org.apache.log4j.ConsoleAppender(
+                        new org.apache.log4j.PatternLayout("%-5p [%t] %m%n"),
+                        org.apache.log4j.ConsoleAppender.SYSTEM_ERR));
+        org.apache.log4j.Logger logger =
+                org.apache.log4j.Logger.getRootLogger();
+        logger.setLevel(org.apache.log4j.Level.INFO);
+        logger.getLoggerRepository().getLogger("eu.clarin").setLevel(
+                org.apache.log4j.Level.DEBUG);
+    }
+
+}
Index: SRUClient/trunk/src/test/java/eu/clarin/sru/client/fcs/TestThreadedClientCallback.java
===================================================================
--- SRUClient/trunk/src/test/java/eu/clarin/sru/client/fcs/TestThreadedClientCallback.java	(revision 6942)
+++ SRUClient/trunk/src/test/java/eu/clarin/sru/client/fcs/TestThreadedClientCallback.java	(revision 6942)
@@ -0,0 +1,144 @@
+/**
+ * This software is copyright (c) 2012-2016 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.concurrent.CountDownLatch;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import eu.clarin.sru.client.SRUCallback;
+import eu.clarin.sru.client.SRUClientException;
+import eu.clarin.sru.client.SRUExplainRequest;
+import eu.clarin.sru.client.SRUExplainResponse;
+import eu.clarin.sru.client.SRUScanRequest;
+import eu.clarin.sru.client.SRUScanResponse;
+import eu.clarin.sru.client.SRUSearchRetrieveRequest;
+import eu.clarin.sru.client.SRUSearchRetrieveResponse;
+import eu.clarin.sru.client.SRUThreadedClient;
+import eu.clarin.sru.client.fcs.ClarinFCSClientBuilder;
+import eu.clarin.sru.client.fcs.ClarinFCSEndpointDescriptionParser;
+
+
+public class TestThreadedClientCallback {
+    private static final Logger logger =
+            LoggerFactory.getLogger(TestThreadedClientCallback.class);
+
+    public static void main(String[] args) {
+        if (args.length > 0) {
+            logger.info("initializing client ...");
+
+            SRUThreadedClient client = new ClarinFCSClientBuilder()
+                    .addDefaultDataViewParsers()
+                    .unknownDataViewAsString()
+                    .enableLegacySupport()
+                    .registerExtraResponseDataParser(
+                            new ClarinFCSEndpointDescriptionParser())
+                    .buildThreadedClient();
+
+            try {
+                final CountDownLatch latch = new CountDownLatch(3);
+
+                /*
+                 * the following requests will be run asynchronously and
+                 * concurrently
+                 * Invoke requests and supply a callback, that
+                 *  a) prints the results
+                 *  b) downs a latch (which is used to make the main-thread wait
+                 *     on the requests to be completed)
+                 */
+                logger.info("submitting 'explain' request ...");
+                SRUExplainRequest request1 =
+                        TestUtils.makeExplainRequest(args[0]);
+                client.explain(request1, new SRUCallback<SRUExplainRequest, SRUExplainResponse>() {
+                    @Override
+                    public void onSuccess(SRUExplainResponse response) {
+                        TestUtils.printExplainResponse(response);
+                        latch.countDown();
+                    }
+
+                    @Override
+                    public void onError(SRUExplainRequest request,
+                            SRUClientException error) {
+                        logger.error("error while performing request", error);
+                        latch.countDown();
+                    }
+                });
+
+                logger.info("submitting 'scan' request ...");
+                SRUScanRequest request2 =
+                        TestUtils.makeScanRequest(args[0]);
+                client.scan(request2, new SRUCallback<SRUScanRequest, SRUScanResponse>() {
+                    @Override
+                    public void onSuccess(SRUScanResponse response) {
+                        TestUtils.printScanResponse(response);
+                        latch.countDown();
+                    }
+
+                    @Override
+                    public void onError(SRUScanRequest request,
+                            SRUClientException error) {
+                        logger.error("error while performing request", error);
+                        latch.countDown();
+                    }
+                });
+
+                logger.info("submitting 'searchRetrieve' request ...");
+                SRUSearchRetrieveRequest request3 =
+                        TestUtils.makeSearchRequest(args[0], null);
+                client.searchRetrieve(request3, new SRUCallback<SRUSearchRetrieveRequest, SRUSearchRetrieveResponse>() {
+                    @Override
+                    public void onSuccess(SRUSearchRetrieveResponse response) {
+                        TestUtils.printSearchResponse(response);
+                        latch.countDown();
+                    }
+
+                    @Override
+                    public void onError(SRUSearchRetrieveRequest request,
+                            SRUClientException error) {
+                        logger.error("error while performing request", error);
+                        latch.countDown();
+                    }
+                });
+
+                latch.await();
+            } catch (Exception e) {
+                logger.error("a fatal error occured while performing request", e);
+            }
+
+            client.shutdown();
+            logger.info("done");
+        } else {
+            System.err.println("missing args");
+            System.exit(64);
+        }
+    }
+
+
+    static {
+        org.apache.log4j.BasicConfigurator.configure(
+                new org.apache.log4j.ConsoleAppender(
+                        new org.apache.log4j.PatternLayout("%-5p [%t] %m%n"),
+                        org.apache.log4j.ConsoleAppender.SYSTEM_ERR));
+        org.apache.log4j.Logger logger =
+                org.apache.log4j.Logger.getRootLogger();
+        logger.setLevel(org.apache.log4j.Level.INFO);
+        logger.getLoggerRepository().getLogger("eu.clarin").setLevel(
+                org.apache.log4j.Level.DEBUG);
+    }
+
+}
Index: SRUClient/trunk/src/test/java/eu/clarin/sru/client/fcs/TestUtils.java
===================================================================
--- SRUClient/trunk/src/test/java/eu/clarin/sru/client/fcs/TestUtils.java	(revision 6942)
+++ SRUClient/trunk/src/test/java/eu/clarin/sru/client/fcs/TestUtils.java	(revision 6942)
@@ -0,0 +1,360 @@
+/**
+ * This software is copyright (c) 2012-2016 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.net.URI;
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Node;
+
+import eu.clarin.sru.client.SRUDiagnostic;
+import eu.clarin.sru.client.SRUExplainRecordData;
+import eu.clarin.sru.client.SRUExplainRequest;
+import eu.clarin.sru.client.SRUExplainResponse;
+import eu.clarin.sru.client.SRUExtraResponseData;
+import eu.clarin.sru.client.SRURecord;
+import eu.clarin.sru.client.SRURecordData;
+import eu.clarin.sru.client.SRURecordPacking;
+import eu.clarin.sru.client.SRURecordXmlEscaping;
+import eu.clarin.sru.client.SRUScanRequest;
+import eu.clarin.sru.client.SRUScanResponse;
+import eu.clarin.sru.client.SRUSearchRetrieveRequest;
+import eu.clarin.sru.client.SRUSearchRetrieveResponse;
+import eu.clarin.sru.client.SRUSurrogateRecordData;
+import eu.clarin.sru.client.SRUTerm;
+import eu.clarin.sru.client.SRUExplainRecordData.ConfigInfo;
+import eu.clarin.sru.client.SRUExplainRecordData.Schema;
+import eu.clarin.sru.client.fcs.ClarinFCSEndpointDescription;
+import eu.clarin.sru.client.fcs.ClarinFCSEndpointDescription.ResourceInfo;
+import eu.clarin.sru.client.fcs.ClarinFCSRecordData;
+import eu.clarin.sru.client.fcs.DataView;
+import eu.clarin.sru.client.fcs.DataViewAdvanced;
+import eu.clarin.sru.client.fcs.DataViewGenericDOM;
+import eu.clarin.sru.client.fcs.DataViewGenericString;
+import eu.clarin.sru.client.fcs.DataViewHits;
+import eu.clarin.sru.client.fcs.Resource;
+
+class TestUtils {
+    private static final Logger logger =
+            LoggerFactory.getLogger(TestUtils.class);
+
+    public static SRUExplainRequest makeExplainRequest(String baseURI) {
+        SRUExplainRequest request = new SRUExplainRequest(baseURI);
+        request.setExtraRequestData("x-indent-response", "4");
+        request.setExtraRequestData("x-fcs-endpoint-description", "true");
+        request.setParseRecordDataEnabled(true);
+        return request;
+    }
+
+
+    public static SRUScanRequest makeScanRequest(String baseURI) {
+        SRUScanRequest request = new SRUScanRequest(baseURI);
+        request.setScanClause("fcs.resource = root");
+        request.setExtraRequestData("x-clarin-resource-info", "true");
+        request.setExtraRequestData("x-indent-response", "4");
+        return request;
+    }
+
+
+    public static SRUSearchRetrieveRequest makeSearchRequest(String baseURI, String query) {
+        if ((query == null) || query.isEmpty()) {
+            query = "'Faustus'";
+        }
+        SRUSearchRetrieveRequest request = new SRUSearchRetrieveRequest(baseURI);
+        request.setQuery("fcs" /*SRUClientConstants.QUERY_TYPE_CQL*/, query);
+//        request.setRecordSchema(ClarinFCSRecordData.LEGACY_RECORD_SCHEMA);
+        request.setMaximumRecords(5);
+        request.setRecordXmlEscaping(SRURecordXmlEscaping.XML);
+        request.setRecordPacking(SRURecordPacking.PACKED);
+        request.setExtraRequestData("x-indent-response", "4");
+        return request;
+    }
+
+
+    public static void printExplainResponse(SRUExplainResponse response) {
+        logger.info("displaying results of 'explain' request ...");
+        if (response.hasDiagnostics()) {
+            for (SRUDiagnostic diagnostic : response.getDiagnostics()) {
+                logger.info("uri={}, message={}, detail={}",
+                        diagnostic.getURI(),
+                        diagnostic.getMessage(),
+                        diagnostic.getDetails());
+            }
+        }
+        if (response.hasRecord()) {
+            SRURecord record = response.getRecord();
+            logger.info("schema = {}", record.getRecordSchema());
+            if (record.isRecordSchema(SRUExplainRecordData.RECORD_SCHEMA)) {
+                dumpExplainRecordData(record.getRecordData());
+            }
+            if (record.hasExtraRecordData()) {
+                logger.info("extraRecordInfo = {}",
+                        record.getExtraRecordData());
+            }
+        }
+        if (response.hasExtraResponseData()) {
+            for (SRUExtraResponseData data : response.getExtraResponseData()) {
+                if (data instanceof ClarinFCSEndpointDescription) {
+                    dumpEndpointDescription(
+                            (ClarinFCSEndpointDescription) data);
+                } else {
+                    logger.info("extraResponseData = {} (class={})",
+                            data.getRootElement(), data.getClass().getName());
+                }
+
+            }
+        }
+    }
+
+
+    public static void printScanResponse(SRUScanResponse response) {
+        logger.info("displaying results of 'scan' request ...");
+        if (response.hasDiagnostics()) {
+            for (SRUDiagnostic diagnostic : response.getDiagnostics()) {
+                logger.info("uri={}, message={}, detail={}",
+                        diagnostic.getURI(),
+                        diagnostic.getMessage(),
+                        diagnostic.getDetails());
+            }
+        }
+        if (response.hasTerms()) {
+            for (SRUTerm term : response.getTerms()) {
+                logger.info("value={}, numberOfRecords={}, displayTerm={}",
+                            term.getValue(),
+                            term.getNumberOfRecords(),
+                            term.getDisplayTerm());
+            }
+        } else {
+            logger.info("no terms");
+        }
+    }
+
+
+    public static void printSearchResponse(SRUSearchRetrieveResponse response) {
+        logger.info("displaying results of 'searchRetrieve' request ...");
+        logger.info("numberOfRecords = {}, nextResultPosition = {}",
+                response.getNumberOfRecords(),
+                response.getNextRecordPosition());
+        if (response.hasDiagnostics()) {
+            for (SRUDiagnostic diagnostic : response.getDiagnostics()) {
+                logger.info("uri={}, message={}, detail={}",
+                        diagnostic.getURI(),
+                        diagnostic.getMessage(),
+                        diagnostic.getDetails());
+            }
+        }
+        if (response.hasRecords()) {
+            for (SRURecord record : response.getRecords()) {
+                logger.info("schema = {}, identifier = {}, position = {}",
+                        record.getRecordSchema(),
+                        record.getRecordIdentifier(),
+                        record.getRecordPosition());
+                if (record.isRecordSchema(ClarinFCSRecordData.RECORD_SCHEMA)) {
+                    ClarinFCSRecordData rd =
+                            (ClarinFCSRecordData) record.getRecordData();
+                    dumpResource(rd.getResource());
+                } else if (record.isRecordSchema(SRUSurrogateRecordData.RECORD_SCHEMA)) {
+                    SRUSurrogateRecordData r =
+                            (SRUSurrogateRecordData) record.getRecordData();
+                    logger.info("SURROGATE DIAGNOSTIC: uri={}, message={}, detail={}",
+                                r.getURI(), r.getMessage(), r.getDetails());
+                } else {
+                    logger.info("UNSUPPORTED SCHEMA: {}",
+                            record.getRecordSchema());
+                }
+            }
+        } else {
+            logger.info("no results");
+        }
+    }
+
+
+    public static void dumpExplainRecordData(SRURecordData recordData) {
+        if (SRUExplainRecordData.RECORD_SCHEMA.equals(recordData.getRecordSchema())) {
+            SRUExplainRecordData data = (SRUExplainRecordData) recordData;
+            logger.info("host={}, port={}, database={}",
+                    data.getServerInfo().getHost(),
+                    data.getServerInfo().getPort(),
+                    data.getServerInfo().getDatabase());
+            List<Schema> schemaInfo = data.getSchemaInfo();
+            if (schemaInfo != null) {
+                for (Schema schema : schemaInfo) {
+                    logger.debug("schema: identifier={}, name={}, " +
+                            "location={}, sort={}, retrieve={}",
+                            schema.getIdentifier(),
+                            schema.getName(),
+                            schema.getLocation(),
+                            schema.getSort(),
+                            schema.getRetrieve());
+                }
+            }
+            ConfigInfo configInfo = data.getConfigInfo();
+            if (configInfo != null) {
+                if (configInfo.getDefaults() != null) {
+                    logger.debug("configInfo/default = {}",
+                            configInfo.getDefaults());
+                }
+                if (configInfo.getSettings() != null) {
+                    logger.debug("configInfo/setting = {}",
+                            configInfo.getSettings());
+                }
+                if (configInfo.getSupports() != null) {
+                    logger.debug("configInfo/supports = {}",
+                            configInfo.getSupports());
+                }
+            }
+        }
+    }
+
+
+    public static void dumpResource(Resource resource) {
+        logger.info("CLARIN-FCS: pid={}, ref={}",
+                resource.getPid(), resource.getRef());
+        if (resource.hasDataViews()) {
+            dumpDataView("CLARIN-FCS: ", resource.getDataViews());
+        }
+        if (resource.hasResourceFragments()) {
+            for (Resource.ResourceFragment fragment : resource.getResourceFragments()) {
+                logger.debug("CLARIN-FCS: ResourceFragment: pid={}, ref={}",
+                        fragment.getPid(), fragment.getRef());
+                if (fragment.hasDataViews()) {
+                    dumpDataView("CLARIN-FCS: ResourceFragment/", fragment.getDataViews());
+                }
+            }
+        }
+    }
+
+
+    private static void dumpEndpointDescription(ClarinFCSEndpointDescription ed) {
+        logger.info("dumping <EndpointDescription> (version={})",
+                ed.getVersion());
+        for (URI capability : ed.getCapabilities()) {
+            logger.info("  capability: {}", capability);
+        } // for
+        for (ClarinFCSEndpointDescription.DataView dataView :
+            ed.getSupportedDataViews()) {
+            logger.info("  supportedDataView: id={}, type={}, policy={}",
+                    dataView.getIdentifier(),
+                    dataView.getMimeType(),
+                    dataView.getDeliveryPolicy());
+        } // for
+        for (ClarinFCSEndpointDescription.Layer layer :
+            ed.getSupportedLayers()) {
+            logger.info("  supportedLayer: id={}, result-id={}, " +
+                    "layer-type={}, encoding={}, qualifier={}, " +
+                    "alt-value-info={}, alt-value-info-uri={}",
+                    layer.getIdentifier(),
+                    layer.getResultId(),
+                    layer.getLayerType(),
+                    layer.getEncoding(),
+                    layer.getQualifier(),
+                    layer.getAltValueInfo(),
+                    layer.getAltValueInfoURI());
+        }
+        dumpResourceInfo(ed.getResources(), 1, "  ");
+    }
+
+
+    private static void dumpResourceInfo(List<ResourceInfo> ris, int depth,
+            String indent) {
+        for (ResourceInfo ri : ris) {
+            logger.info("{}[depth={}] <ResourceInfo>", indent, depth);
+            logger.info("{}    pid={}", indent, ri.getPid());
+            logger.info("{}    title: {}", indent, ri.getTitle());
+            if (ri.getDescription() != null) {
+                logger.info("{}    description: {}",
+                        indent, ri.getDescription());
+            }
+            if (ri.getLandingPageURI() != null) {
+                logger.info("{}    landingPageURI: {}",
+                        indent, ri.getLandingPageURI());
+            }
+            for (ClarinFCSEndpointDescription.DataView dv :
+                ri.getAvailableDataViews()) {
+                logger.info("{}    available dataviews: type={}, policy={}",
+                        indent, dv.getMimeType(), dv.getDeliveryPolicy());
+            }
+            for (ClarinFCSEndpointDescription.Layer l :
+                ri.getAvailableLayers()) {
+                logger.info("{}    available layers: result-id={}, layer-type={}",
+                        indent, l.getResultId(), l.getLayerType());
+            }
+            if (ri.hasSubResources()) {
+                dumpResourceInfo(ri.getSubResources(),
+                        depth + 1, indent + "  ");
+            }
+        }
+    }
+
+
+    private static void dumpDataView(String s, List<DataView> dataviews) {
+        for (DataView dataview : dataviews) {
+            logger.info("{}DataView: type={}, pid={}, ref={}",
+                    s, dataview.getMimeType(), dataview.getPid(),
+                    dataview.getRef());
+            if (dataview instanceof DataViewGenericDOM) {
+                final DataViewGenericDOM view = (DataViewGenericDOM) dataview;
+                final Node root = view.getDocument().getFirstChild();
+                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 (generic string): data = {}",
+                        s, view.getContent());
+            } else if (dataview instanceof DataViewHits) {
+                final DataViewHits hits = (DataViewHits) dataview;
+                logger.info("{}DataView: {}",
+                        s, addHitHighlights(hits));
+            } else if (dataview instanceof DataViewAdvanced) {
+                final DataViewAdvanced adv = (DataViewAdvanced) dataview;
+                logger.info("{}DataView: unit={}",
+                        s, adv.getUnit());
+                for (DataViewAdvanced.Layer layer : adv.getLayers()) {
+                    logger.info("{}DataView: Layer: id={}",
+                            s, layer.getId());
+                    for (DataViewAdvanced.Span span : layer.getSpans()) {
+                        logger.info("{}DataView:   Span: start={}, end={}, content={}",
+                                s, span.getStartOffset(), span.getEndOffset(), span.getContent());
+                    }
+                }
+            } 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();
+    }
+
+} // class TestUtils
