Index: SRUClient/trunk/src/main/java/eu/clarin/sru/client/SRUClient.java
===================================================================
--- SRUClient/trunk/src/main/java/eu/clarin/sru/client/SRUClient.java	(revision 2881)
+++ SRUClient/trunk/src/main/java/eu/clarin/sru/client/SRUClient.java	(revision 2936)
@@ -56,6 +56,4 @@
     private List<SRUDiagnostic> diagnostics;
     private DocumentFragment extraResponseData;
-    /* explain */
-    private SRURecord record;
     /* scan */
     private List<SRUTerm> terms;
@@ -64,6 +62,7 @@
     private String resultSetId;
     private int resultSetIdleTime;
+    private int nextRecordPosition;
+    /* explain/searchRetrieve */
     private List<SRURecord> records;
-    private int nextRecordPosition;
     /* statistics */
     private int totalBytesTransferred;
@@ -167,17 +166,14 @@
     /**
      * Register a record data parser.
-     *
+     * 
      * @param parser
      *            a parser instance
-     * @throws SRUClientException
-     *             if a parser handing the same record schema is already
-     *             registered
      * @throws NullPointerException
      *             if any required argument is <code>null</code>
      * @throws IllegalArgumentException
-     *             if the supplied parser is invalid
-     */
-    public void registerRecordParser(SRURecordDataParser parser)
-            throws SRUClientException {
+     *             if the supplied parser is invalid or a parser handing the
+     *             same record schema is already registered
+     */
+    public void registerRecordParser(SRURecordDataParser parser) {
         client.registerRecordParser(parser);
     }
@@ -202,4 +198,8 @@
         try {
             client.explain(request, handler);
+            SRURecord record = null;
+            if ((records != null) && !records.isEmpty()) {
+                record = records.get(0);
+            }
             return new SRUExplainResponse(request,
                     diagnostics,
@@ -313,6 +313,4 @@
         diagnostics           = null;
         extraResponseData     = null;
-        /* explain */
-        record                = null;
         /* scan */
         terms                 = null;
@@ -321,6 +319,7 @@
         resultSetId           = null;
         resultSetIdleTime     = -1;
+        nextRecordPosition    = -1;
+        /* explain/searchRetrieve */
         records               = null;
-        nextRecordPosition    = -1;
         /* statistics */
         totalBytesTransferred = -1;
Index: SRUClient/trunk/src/main/java/eu/clarin/sru/client/SRUExplainHandler.java
===================================================================
--- SRUClient/trunk/src/main/java/eu/clarin/sru/client/SRUExplainHandler.java	(revision 2881)
+++ SRUClient/trunk/src/main/java/eu/clarin/sru/client/SRUExplainHandler.java	(revision 2936)
@@ -76,3 +76,71 @@
             throws XMLStreamException, SRUClientException;
 
+    /**
+     * Receive notifications of the start of the enumeration of records in the
+     * response.
+     *
+     * @param numberOfRecords
+     *            the number of records or <code>-1</code> if not available
+     * @param resultSetId
+     *            the result set id or <code>null</code> if not available
+     * @param resultSetIdleTime
+     *            the result set idle time or <code>-1</code> if not available
+     * @throws SRUClientException
+     *             any SRU exception, possibly wrapping another exception
+     */
+    public void onStartRecords(int numberOfRecords, String resultSetId,
+            int resultSetIdleTime) throws SRUClientException;
+
+
+    /**
+     * Receive notifications of the end of the enumeration of records in the
+     * response.
+     *
+     * @param nextRecordPosition
+     *            the next record position or <code>-1</code> if not available
+     * @throws SRUClientException
+     *             any SRU exception, possibly wrapping another exception
+     */
+    public void onFinishRecords(int nextRecordPosition)
+            throws SRUClientException;
+
+
+    /**
+     * Receive notification of a record in the result set.
+     *
+     * @param identifier
+     *            identifier of the record or <code>null</code> if not available
+     * @param position
+     *            position of the record in the result set or <code>-1</code> if
+     *            not available
+     * @param data
+     *            the parsed record data
+     * @throws SRUClientException
+     *             any SRU exception, possibly wrapping another exception
+     * @see SRURecordData
+     * @see SRURecordDataParser
+     */
+    public void onRecord(String identifier, int position, SRURecordData data)
+            throws SRUClientException;
+
+
+    /**
+     * Receive notification of extra record data.
+     *
+     * @param identifier
+     *            identifier of the record or <code>null</code> if not available
+     * @param position
+     *            position of the record in the result set or <code>-1</code> if
+     *            not available
+     * @param reader
+     *            a {@link XMLStreamReader} to parse the extra term data
+     * @throws XMLStreamException
+     *             an error occurred while parsing the response
+     * @throws SRUClientException
+     *             any SRU exception, possibly wrapping another exception
+     */
+    public void onExtraRecordData(String identifier, int position,
+            XMLStreamReader reader) throws XMLStreamException,
+            SRUClientException;
+
 } // interface SRUExplainHandler
Index: SRUClient/trunk/src/main/java/eu/clarin/sru/client/SRUExplainRecordData.java
===================================================================
--- SRUClient/trunk/src/main/java/eu/clarin/sru/client/SRUExplainRecordData.java	(revision 2936)
+++ SRUClient/trunk/src/main/java/eu/clarin/sru/client/SRUExplainRecordData.java	(revision 2936)
@@ -0,0 +1,115 @@
+/**
+ * This software is copyright (c) 2011-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;
+
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * A record data implementation for SRU explain record data conforming to the
+ * Zeerex schema.
+ */
+public class SRUExplainRecordData implements SRURecordData {
+    public static final String RECORD_SCHEMA = "http://explain.z3950.org/dtd/2.0/";
+
+    public static class ServerInfo {
+        private final String host;
+        private final int port;
+        private final String database;
+        private final SRUVersion version;
+        private final Set<String> transport;
+
+        public ServerInfo(String host, int port, String database,
+                String protocol, SRUVersion version, Set<String> transport) {
+            if (host == null) {
+                throw new NullPointerException("host == null");
+            }
+            if (host.isEmpty()) {
+                throw new IllegalArgumentException("host is empty");
+            }
+            if ((port < 0) || (port > 65535)) {
+                throw new IllegalArgumentException("port < 0 || port > 65535");
+            }
+            if (database == null) {
+                throw new NullPointerException("database == null");
+            }
+            if (database.isEmpty()) {
+                throw new IllegalArgumentException("database is empty");
+            }
+            if (version == null) {
+                throw new NullPointerException("version == null");
+            }
+            if (transport == null) {
+                throw new NullPointerException("transport == null");
+            }
+            this.host      = host;
+            this.port      = port;
+            this.database  = database;
+            this.version   = version;
+            this.transport = Collections.unmodifiableSet(transport);
+        }
+
+
+        public String getHost() {
+            return host;
+        }
+
+
+        public int getPort() {
+            return port;
+        }
+
+
+        public String getDatabase() {
+            return database;
+        }
+
+
+        public SRUVersion getVersion() {
+            return version;
+        }
+
+
+        public Set<String> getTransport() {
+            return transport;
+        }
+    } // class ServerInfo
+    private final ServerInfo serverInfo;
+
+
+    public SRUExplainRecordData(ServerInfo serverInfo) {
+        this.serverInfo = serverInfo;
+    }
+
+
+    @Override
+    public boolean isTransient() {
+        return false;
+    }
+
+
+    @Override
+    public String getRecordSchema() {
+        return RECORD_SCHEMA;
+    }
+
+
+    public ServerInfo getServerInfo() {
+        return serverInfo;
+    }
+
+} // class SRUExplainRecordData
Index: SRUClient/trunk/src/main/java/eu/clarin/sru/client/SRUExplainRecordDataParser.java
===================================================================
--- SRUClient/trunk/src/main/java/eu/clarin/sru/client/SRUExplainRecordDataParser.java	(revision 2936)
+++ SRUClient/trunk/src/main/java/eu/clarin/sru/client/SRUExplainRecordDataParser.java	(revision 2936)
@@ -0,0 +1,177 @@
+/**
+ * This software is copyright (c) 2011-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;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import eu.clarin.sru.client.SRUExplainRecordData.ServerInfo;
+
+
+/**
+ * This class implements a (partial) record data parser for SRU explain record
+ * data conforming to the ZEEREX schema
+ */
+public class SRUExplainRecordDataParser implements SRURecordDataParser {
+    private static final String ZEEREX_NS = SRUExplainRecordData.RECORD_SCHEMA;
+    private static final String VERSION_1_1     = "1.1";
+    private static final String VERSION_1_2     = "1.2";
+    private static final String TRANSPORT_HTTP  = "http";
+    private static final String TRANSPORT_HTTPS = "https";
+    private static final Logger logger =
+            LoggerFactory.getLogger(SRUExplainRecordDataParser.class);
+
+    @Override
+    public String getRecordSchema() {
+        return SRUExplainRecordData.RECORD_SCHEMA;
+    }
+
+
+    @Override
+    public SRURecordData parse(XMLStreamReader reader, SRUVersion version)
+            throws XMLStreamException, SRUClientException {
+        logger.debug("parsing explain record data for version {}", version);
+
+        // explain
+        XmlStreamReaderUtils.readStart(reader, ZEEREX_NS, "explain", true);
+
+        // explain/serverInfo
+        ServerInfo serverInfo = parseServerInfo(reader);
+
+        // explain/databaseInfo
+        if (XmlStreamReaderUtils.readStart(reader, ZEEREX_NS, "databaseInfo", false)) {
+            logger.debug("databaseInfo");
+            XmlStreamReaderUtils.readEnd(reader, ZEEREX_NS, "databaseInfo", true);
+        }
+
+        // explain/metaInfo
+        if (XmlStreamReaderUtils.readStart(reader, ZEEREX_NS, "metaInfo", false)) {
+            logger.debug("metaInfo");
+            XmlStreamReaderUtils.readEnd(reader, ZEEREX_NS, "metaInfo", true);
+        }
+
+        // explain/indexInfo
+        while (XmlStreamReaderUtils.readStart(reader, ZEEREX_NS, "indexInfo", false)) {
+            logger.debug("indexInfo");
+            for (;;) {
+                /*
+                 * FIXME: SRU 2.0 has *either* <set> or <index>
+                 * check with SRU 1.2 ...
+                 */
+                if (XmlStreamReaderUtils.readStart(reader, ZEEREX_NS, "set", false, true)) {
+                    logger.debug("set");
+                    // FIXME: read attributes
+                    XmlStreamReaderUtils.consumeStart(reader);
+
+                    XmlStreamReaderUtils.readEnd(reader, ZEEREX_NS, "set", true);
+                } else if (XmlStreamReaderUtils.readStart(reader, ZEEREX_NS, "index", false, true)) {
+                    logger.debug("index");
+                    // FIXME: read attributes
+                    XmlStreamReaderUtils.consumeStart(reader);
+                    XmlStreamReaderUtils.readEnd(reader, ZEEREX_NS, "index", true);
+                } else {
+                    break;
+                }
+            }
+            XmlStreamReaderUtils.readEnd(reader, ZEEREX_NS, "indexInfo", true);
+        } // while
+
+        XmlStreamReaderUtils.readEnd(reader, ZEEREX_NS, "explain", true);
+        return new SRUExplainRecordData(serverInfo);
+    }
+
+
+    private static ServerInfo parseServerInfo(XMLStreamReader reader)
+            throws XMLStreamException, SRUClientException {
+        XmlStreamReaderUtils.readStart(reader, ZEEREX_NS,
+                "serverInfo", true, true);
+        String protocol = XmlStreamReaderUtils.readAttributeValue(reader,
+                null, "protocol");
+
+        SRUVersion version = SRUVersion.VERSION_1_2;
+        String s = XmlStreamReaderUtils.readAttributeValue(reader, null,
+                "version");
+        if (s != null) {
+            if (VERSION_1_1.equals(s)) {
+                version = SRUVersion.VERSION_1_1;
+            } else if (VERSION_1_2.equals(s)) {
+                version = SRUVersion.VERSION_1_2;
+            } else {
+                throw new SRUClientException(
+                        "invalid or unsupported version: " + s);
+            }
+        }
+
+        Set<String> transports = new HashSet<String>();
+        s = XmlStreamReaderUtils.readAttributeValue(reader,
+                null, "transport");
+        if (s != null) {
+            for (String i : s.split("\\s+")) {
+                String t = null;
+                if (TRANSPORT_HTTP.equalsIgnoreCase(i)) {
+                    t = TRANSPORT_HTTP;
+                } else if (TRANSPORT_HTTPS.equalsIgnoreCase(i)) {
+                    t = TRANSPORT_HTTPS;
+                } else {
+                    throw new SRUClientException("invalid transport: " + i);
+                }
+                if (t != null) {
+                    if (!transports.contains(t)) {
+                        transports.add(t);
+                    } else {
+                        // FIXME: error message
+                        logger.warn("transport  {} was already listed", s);
+                    }
+                }
+
+            } // for
+        } else {
+            transports.add(TRANSPORT_HTTP);
+        }
+        XmlStreamReaderUtils.consumeStart(reader);
+
+        String host = XmlStreamReaderUtils.readContent(reader, ZEEREX_NS,
+                "host", true);
+        int port = XmlStreamReaderUtils.readContent(reader, ZEEREX_NS,
+                "port", true, -1);
+        if ((port < 0) || (port > 65535)) {
+            // FIXME: error message
+            throw new SRUClientException("invalid port number (" + port + ")");
+        }
+        String database = XmlStreamReaderUtils.readContent(reader, ZEEREX_NS,
+                "database", true);
+        if (XmlStreamReaderUtils.readStart(reader, ZEEREX_NS,
+                "authentication", false)) {
+            XmlStreamReaderUtils.readEnd(reader, ZEEREX_NS,
+                    "authentication", true);
+        }
+        XmlStreamReaderUtils.readEnd(reader, ZEEREX_NS, "serverInfo", true);
+        logger.debug(
+                "serverInfo: host={}, port={}, database={}, version={}, protocol={}, transport={}",
+                new Object[] { host, port, database, version, protocol,
+                        transports });
+        return new ServerInfo(host, port, database, protocol, version,
+                transports);
+    }
+
+} // class SRUExplainRecordDataParser
Index: SRUClient/trunk/src/main/java/eu/clarin/sru/client/SRURecordDataParser.java
===================================================================
--- SRUClient/trunk/src/main/java/eu/clarin/sru/client/SRURecordDataParser.java	(revision 2881)
+++ SRUClient/trunk/src/main/java/eu/clarin/sru/client/SRURecordDataParser.java	(revision 2936)
@@ -39,4 +39,6 @@
      * @param reader
      *            a {@link XMLStreamReader} to parse the record data
+     * @param version
+     *            the {@link SRUVersion} that was used to encode the record
      * @return the parsed record
      * @throws XMLStreamException
@@ -46,5 +48,5 @@
      * @see SRURecordData
      */
-    public SRURecordData parse(XMLStreamReader reader)
+    public SRURecordData parse(XMLStreamReader reader, SRUVersion version)
             throws XMLStreamException, SRUClientException;
 
Index: SRUClient/trunk/src/main/java/eu/clarin/sru/client/SRUSimpleClient.java
===================================================================
--- SRUClient/trunk/src/main/java/eu/clarin/sru/client/SRUSimpleClient.java	(revision 2881)
+++ SRUClient/trunk/src/main/java/eu/clarin/sru/client/SRUSimpleClient.java	(revision 2936)
@@ -84,5 +84,6 @@
     private final HttpClient httpClient;
     private final XmlStreamReaderProxy proxy = new XmlStreamReaderProxy();
-
+    private final SRUExplainRecordDataParser explainRecordParser =
+            new SRUExplainRecordDataParser();
 
     /**
@@ -193,14 +194,11 @@
      * @param parser
      *            a parser instance
-     * @throws SRUClientException
-     *             if a parser handing the same record schema is already
-     *             registered
      * @throws NullPointerException
      *             if any required argument is <code>null</code>
      * @throws IllegalArgumentException
-     *             if the supplied parser is invalid
+     *             if the supplied parser is invalid or a parser handing the
+     *             same record schema is already registered
      */
-    public void registerRecordParser(SRURecordDataParser parser)
-            throws SRUClientException {
+    public void registerRecordParser(SRURecordDataParser parser) {
         if (parser == null) {
             throw new NullPointerException("parser == null");
@@ -218,5 +216,5 @@
             parsers.put(recordSchema, parser);
         } else {
-            throw new SRUClientException(
+            throw new IllegalArgumentException(
                     "record data parser already registered: " + recordSchema);
         }
@@ -247,5 +245,5 @@
             throw new NullPointerException("handler == null");
         }
-        logger.debug("explain");
+        logger.debug("performing explain request");
 
         final long ts_start = System.nanoTime();
@@ -332,5 +330,6 @@
             throw new NullPointerException("handler == null");
         }
-        logger.debug("searchRetrieve: scanClause = {}", request.getScanClause());
+        logger.debug("performing scan request: scanClause = {}",
+                request.getScanClause());
 
         final long ts_start = System.nanoTime();
@@ -417,5 +416,6 @@
             throw new NullPointerException("handler == null");
         }
-        logger.debug("searchRetrieve: query = {}", request.getQuery());
+        logger.debug("performing searchRetrieve request: query = {}",
+                request.getQuery());
 
         final long ts_start = System.nanoTime();
@@ -483,5 +483,5 @@
         HttpResponse response = null;
         try {
-            logger.debug("performing HTTP request: {}", uri.toString());
+            logger.debug("submitting HTTP request: {}", uri.toString());
             try {
                 request = new HttpGet(uri);
@@ -535,7 +535,16 @@
 
     private void parseExplainResponse(final SRUXMLStreamReader reader,
-            final SRUAbstractRequest request, final SRUExplainHandler handler)
+            final SRUExplainRequest request, final SRUExplainHandler handler)
             throws SRUClientException {
         logger.debug("parsing 'explain' response");
+// FIXME: ship explain record data for now
+//        doParseExplainResponse(reader, request, handler, true);
+        doParseExplainResponse(reader, request, handler, false);
+    }
+
+
+    private void doParseExplainResponse(SRUXMLStreamReader reader,
+            SRUAbstractRequest request, SRUExplainHandler handler,
+            boolean parseRecordData) throws SRUClientException {
         try {
             // explainResponse
@@ -549,26 +558,95 @@
             // explainResponse/record
             reader.readStart(SRU_NS, "record", true);
-
-            String schema = reader.readContent(SRU_NS, "recordSchema", true);
-
-            SRURecordPacking packing = parseRecordPacking(reader, strictMode);
-
-            logger.debug("schema = {}, packing = {}", schema, packing);
-
-            // explainResponse/record/recordData
-            reader.readStart(SRU_NS, "recordData", true);
-            reader.readEnd(SRU_NS, "recordData", true);
-
-            // explainResponse/record/recordPosition
-            if (reader.readStart(SRU_NS, "recordPosition", false)) {
-                reader.readEnd(SRU_NS, "recordPosition", true);
-            }
-
-            // explainResponse/record/extraRecordData
-            if (reader.readStart(SRU_NS, "extraRecordData", false)) {
-                reader.readEnd(SRU_NS, "extraRecordData", true);
-            }
-
-            reader.readEnd(SRU_NS, "record");
+            if (parseRecordData) {
+                handler.onStartRecords(-1, null, -1);
+
+                SRURecordPacking packing = null;
+                if (!strictMode && reader.peekStart(SRU_NS, "recordPacking")) {
+                    packing = parseRecordPacking(reader, false);
+                    if (packing != null) {
+                        logger.error("element <recordPacking> must apperear after element <recordSchema> within element <record>");
+                    }
+                }
+                String schema =
+                        reader.readContent(SRU_NS, "recordSchema", true);
+                if (packing == null) {
+                    packing = parseRecordPacking(reader, strictMode);
+                }
+                logger.debug("schema = {}, packing = {}", schema, packing);
+
+                // explainResponse/record/recordData
+                reader.readStart(SRU_NS, "recordData", true);
+                reader.consumeWhitespace();
+
+                SRURecordData recordData = null;
+                SRUXMLStreamReader recordReader = null;
+
+                if (packing == SRURecordPacking.STRING) {
+                    /*
+                     * read content into temporary buffer and then use a new XML
+                     * reader to parse record data
+                     */
+                    final String data = reader.readString(true);
+                    InputStream in = new ByteArrayInputStream(data.getBytes());
+                    // FIXME: namespace context?
+                    recordReader = createReader(in, false);
+                } else {
+                    recordReader = reader;
+                }
+
+                if (!SRUExplainRecordData.RECORD_SCHEMA.equals(schema)) {
+                    // FIXME: message
+                    throw new SRUClientException("bad record schema");
+                }
+                try {
+                    proxy.reset(recordReader);
+                    recordData = explainRecordParser.parse(proxy, version);
+                } catch (XMLStreamException e) {
+                    throw new SRUClientException(
+                            "error parsing explain record", e);
+                }
+                if (recordData == null) {
+                    // FIXME: error message
+                    throw new SRUClientException(
+                            "error parsing explain record");
+                }
+                if (packing == SRURecordPacking.STRING) {
+                    recordReader.closeCompletly();
+                }
+                reader.consumeWhitespace();
+                reader.readEnd(SRU_NS, "recordData", true);
+
+                if (version == SRUVersion.VERSION_1_2) {
+                    reader.readContent(SRU_NS, "recordIdentifier", false);
+                }
+                reader.readContent(SRU_NS, "recordPosition", false, -1);
+
+                // notify handler
+                handler.onRecord(null, -1, recordData);
+
+                if (reader.readStart(SRU_NS, "extraRecordData", false)) {
+                    reader.consumeWhitespace();
+                    proxy.reset(reader);
+                    try {
+                        handler.onExtraRecordData(null, -1, proxy);
+                    } catch (XMLStreamException e) {
+                        throw new SRUClientException("handler "
+                                + "triggered error while parsing "
+                                + "'extraRecordData'", e);
+                    }
+                    reader.consumeWhitespace();
+                    reader.readEnd(SRU_NS, "extraRecordData", true);
+                }
+
+                handler.onFinishRecords(-1);
+
+                reader.readEnd(SRU_NS, "record");
+            } else {
+                /*
+                 * do not really parse record and skip everything until <record>
+                 * end tag
+                 */
+                reader.readEnd(SRU_NS, "record", true);
+            }
 
             // explainResponse/echoedExplainRequest
@@ -625,5 +703,5 @@
              */
             if (reader.peekStart(SRU_NS, "explainResponse")) {
-                parseExplainResponse(reader, request, new SRUExplainHandler() {
+                doParseExplainResponse(reader, request, new SRUExplainHandler() {
                     @Override
                     public void onRequestStatistics(int bytes, long millisTotal,
@@ -643,5 +721,31 @@
                         handler.onDiagnostics(diagnostics);
                     }
-                });
+
+
+                    @Override
+                    public void onStartRecords(int numberOfRecords,
+                            String resultSetId, int resultSetIdleTime)
+                            throws SRUClientException {
+                    }
+
+
+                    @Override
+                    public void onFinishRecords(int nextRecordPosition)
+                            throws SRUClientException {
+                    }
+
+
+                    @Override
+                    public void onRecord(String identifier, int position,
+                            SRURecordData data) throws SRUClientException {
+                    }
+
+
+                    @Override
+                    public void onExtraRecordData(String identifier,
+                            int position, XMLStreamReader reader)
+                            throws XMLStreamException, SRUClientException {
+                    }
+                }, false);
             } else {
                 logger.debug("parsing 'scanResponse' response");
@@ -665,6 +769,6 @@
 
                         // scanResponse/terms/value
-                        String value = reader
-                                .readContent(SRU_NS, "value", true);
+                        String value =
+                                reader.readContent(SRU_NS, "value", true);
 
                         // scanResponse/terms/numberOfRecords
@@ -776,5 +880,5 @@
              */
             if (reader.peekStart(SRU_NS, "explainResponse")) {
-                parseExplainResponse(reader, request, new SRUExplainHandler() {
+                doParseExplainResponse(reader, request, new SRUExplainHandler() {
                     @Override
                     public void onRequestStatistics(int bytes, long millisTotal,
@@ -794,5 +898,31 @@
                         handler.onDiagnostics(diagnostics);
                     }
-                });
+
+
+                    @Override
+                    public void onStartRecords(int numberOfRecords,
+                            String resultSetId, int resultSetIdleTime)
+                            throws SRUClientException {
+                    }
+
+
+                    @Override
+                    public void onFinishRecords(int nextRecordPosition)
+                            throws SRUClientException {
+                    }
+
+
+                    @Override
+                    public void onRecord(String identifier, int position,
+                            SRURecordData data) throws SRUClientException {
+                    }
+
+
+                    @Override
+                    public void onExtraRecordData(String identifier,
+                            int position, XMLStreamReader reader)
+                            throws XMLStreamException, SRUClientException {
+                    }
+                }, false);
             } else {
                 logger.debug("parsing 'searchRetrieve' response");
@@ -824,159 +954,194 @@
                 // searchRetrieveResponse/results
                 if (numberOfRecords > 0) {
-                    reader.readStart(SRU_NS, "records", true);
-
-                    // searchRetrieveResponse/records/record
-                    boolean first = true;
-                    while (reader.readStart(SRU_NS, "record", first)) {
-                        if (first) {
-                            first = false;
-                            handler.onStartRecords(numberOfRecords,
-                                    resultSetId, resultSetIdleTime);
-                        }
-
-                        String schema = reader.readContent(SRU_NS,
-                                "recordSchema", true);
-
-                        SRURecordPacking packing =
-                                parseRecordPacking(reader, strictMode);
-
-                        logger.debug("schema = {}, packing = {}, " +
-                                "requested packing = {}",
-                                new Object[] { schema, packing,
-                                        request.getRecordPacking() });
-
-                        if ((request.getRecordPacking() != null) &&
-                                (packing != request.getRecordPacking())) {
-                            final SRURecordPacking p =
-                                    request.getRecordPacking();
-                            logger.error("requested '{}' record packing, but " +
-                                "server responded with '{}' record packing",
-                                    p.getStringValue(),
-                                    packing.getStringValue());
-                            if (strictMode) {
-                                throw new SRUClientException("requested '" +
-                                        p.getStringValue() +
-                                        "' record packing, but server " +
-                                        "responded with '" +
-                                        packing.getStringValue() +
-                                        "' record packing");
+                    /*
+                     * some endpoints set numberOfRecords but do not serialize
+                     * any records, e.g if requested record schema is not
+                     * supported
+                     */
+                    int recordCount = 0;
+                    if (reader.readStart(SRU_NS, "records", false)) {
+                        // searchRetrieveResponse/records/record
+                        boolean first = true;
+                        while (reader.readStart(SRU_NS, "record", first)) {
+                            if (first) {
+                                first = false;
+                                handler.onStartRecords(numberOfRecords,
+                                        resultSetId, resultSetIdleTime);
                             }
-                        }
-
-                        // searchRetrieveResponse/record/recordData
-                        reader.readStart(SRU_NS, "recordData", true);
-                        reader.consumeWhitespace();
-
-                        SRURecordData recordData = null;
-                        SRUDiagnostic surrogate = null;
-                        SRUXMLStreamReader recordReader = null;
-
-                        if (packing == SRURecordPacking.STRING) {
+
                             /*
-                             * read content into temporary buffer and then use
-                             * a new XML reader to parse record data
+                             * common error: recordPacking before recordSchema
                              */
-                            final String data = reader.readString(true);
-                            InputStream in =
-                                    new ByteArrayInputStream(data.getBytes());
-                            // FIXME: namespace context?
-                            recordReader = createReader(in, false);
-                        } else {
-                            recordReader = reader;
-                        }
-
-                        if (SRU_DIAGNOSTIC_RECORD_SCHEMA.equals(schema)) {
-                            surrogate = parseDiagnostic(recordReader,
-                                    true, strictMode);
-                        } else {
-                            SRURecordDataParser parser = findParser(schema);
-                            if (parser != null) {
+                            SRURecordPacking packing = null;
+                            if (!strictMode &&
+                                    reader.peekStart(SRU_NS, "recordPacking")) {
+                                packing = parseRecordPacking(reader, false);
+                                if (packing != null) {
+                                    logger.error("element <recordPacking> " +
+                                            "must appear after element " +
+                                            "<recordSchema> within " +
+                                            "element <record>");
+                                }
+                            }
+                            String schema = reader.readContent(SRU_NS,
+                                    "recordSchema", true);
+                            if (packing == null) {
+                                packing = parseRecordPacking(reader, strictMode);
+                            }
+
+                            logger.debug("schema = {}, packing = {}, " +
+                                    "requested packing = {}",
+                                    new Object[] { schema, packing,
+                                            request.getRecordPacking() });
+
+                            if ((request.getRecordPacking() != null) &&
+                                    (packing != request.getRecordPacking())) {
+                                final SRURecordPacking p =
+                                        request.getRecordPacking();
+                                logger.error("requested '{}' record packing, " +
+                                        "but server responded with '{}' " +
+                                        "record packing",
+                                        p.getStringValue(),
+                                        packing.getStringValue());
+                                if (strictMode) {
+                                    throw new SRUClientException("requested '" +
+                                            p.getStringValue() +
+                                            "' record packing, but server " +
+                                            "responded with '" +
+                                            packing.getStringValue() +
+                                            "' record packing");
+                                }
+                            }
+
+                            // searchRetrieveResponse/record/recordData
+                            reader.readStart(SRU_NS, "recordData", true);
+                            reader.consumeWhitespace();
+
+                            SRURecordData recordData = null;
+                            SRUDiagnostic surrogate = null;
+                            SRUXMLStreamReader recordReader = null;
+
+                            if (packing == SRURecordPacking.STRING) {
+                                /*
+                                 * read content into temporary buffer and then
+                                 * use a new XML reader to parse record data
+                                 */
+                                final String data = reader.readString(true);
+                                InputStream in = new ByteArrayInputStream(
+                                        data.getBytes());
+                                // FIXME: namespace context?
+                                recordReader = createReader(in, false);
+                            } else {
+                                recordReader = reader;
+                            }
+
+                            if (SRU_DIAGNOSTIC_RECORD_SCHEMA.equals(schema)) {
+                                surrogate = parseDiagnostic(recordReader, true,
+                                        strictMode);
+                            } else {
+                                SRURecordDataParser parser = findParser(schema);
+                                if (parser != null) {
+                                    try {
+                                        proxy.reset(recordReader);
+                                        recordData =
+                                                parser.parse(proxy, version);
+                                    } catch (XMLStreamException e) {
+                                        throw new SRUClientException(
+                                                "error parsing record", e);
+                                    }
+                                    if (recordData == null) {
+                                        logger.debug("record parser did not parse "
+                                                + "record correctly and returned "
+                                                + "null; injecting client side "
+                                                + "surrogate diagnostic");
+                                        surrogate = new SRUDiagnostic(
+                                                SRUClientDiagnostics.DIAG_RECORD_PARSER_NULL,
+                                                null,
+                                                "Record parser for schema '" +
+                                                        schema +
+                                                        "' did not " +
+                                                        "parse record correctly " +
+                                                        "and errornously " +
+                                                        "returned null.");
+                                    }
+                                } else {
+                                    /*
+                                     * no record parser found, inject a
+                                     * surrogate diagnostic
+                                     */
+                                    logger.debug(
+                                            "no record data parser found "
+                                                    + "for schema '{}'; injecting client "
+                                                    + "side surrogate diagnostic",
+                                            schema);
+                                    surrogate = new SRUDiagnostic(
+                                            SRUClientDiagnostics.DIAG_NO_RECORD_PARSER,
+                                            schema,
+                                            "No record data parser for schema '" +
+                                                    schema + "' found.");
+                                }
+                            }
+
+                            if (packing == SRURecordPacking.STRING) {
+                                recordReader.closeCompletly();
+                            }
+
+                            reader.consumeWhitespace();
+                            reader.readEnd(SRU_NS, "recordData", true);
+
+                            String identifier = null;
+                            if (version == SRUVersion.VERSION_1_2) {
+                                identifier = reader.readContent(SRU_NS,
+                                        "recordIdentifier", false);
+                            }
+
+                            int position = reader.readContent(SRU_NS,
+                                    "recordPosition", false, -1);
+
+                            logger.debug("recordIdentifier = {}, " +
+                                    "recordPosition = {}",
+                                    identifier, position);
+
+                            // notify handler
+                            if (surrogate != null) {
+                                handler.onSurrogateRecord(identifier,
+                                        position, surrogate);
+                            } else {
+                                if (recordData != null) {
+                                    handler.onRecord(identifier,
+                                            position, recordData);
+                                }
+                            }
+
+                            if (reader.readStart(SRU_NS,
+                                    "extraRecordData", false)) {
+                                reader.consumeWhitespace();
+                                proxy.reset(reader);
                                 try {
-                                    proxy.reset(recordReader);
-                                    recordData = parser.parse(proxy);
+                                    handler.onExtraRecordData(identifier,
+                                            position, proxy);
                                 } catch (XMLStreamException e) {
-                                    throw new SRUClientException(
-                                            "error parsing record", e);
+                                    throw new SRUClientException("handler " +
+                                            "triggered error while parsing " +
+                                            "'extraRecordData'", e);
                                 }
-                                if (recordData == null) {
-                                    logger.debug("record parser did not parse " +
-                                            "record correctly and returned " +
-                                            "null; injecting client side " +
-                                            "surrogate diagnostic");
-                                    surrogate = new SRUDiagnostic(
-                                            SRUClientDiagnostics.DIAG_RECORD_PARSER_NULL,
-                                            null, "Record parser for schema '" +
-                                                    schema + "' did not " +
-                                                    "parse record correctly " +
-                                                    "and errornously " +
-                                                    "returned null.");
-                                }
-                            } else {
-                                /*
-                                 * no record parser found, inject a
-                                 * surrogate diagnostic
-                                 */
-                                logger.debug("no record data parser found " +
-                                        "for schema '{}'; injecting client " +
-                                        "side surrogate diagnostic", schema);
-                                surrogate = new SRUDiagnostic(
-                                        SRUClientDiagnostics.DIAG_NO_RECORD_PARSER,
-                                        schema,
-                                        "No record data parser for schema '" +
-                                                schema + "' found.");
+                                reader.consumeWhitespace();
+                                reader.readEnd(SRU_NS, "extraRecordData", true);
                             }
-                        }
-
-                        if (packing == SRURecordPacking.STRING) {
-                            recordReader.closeCompletly();
-                        }
-
-                        reader.consumeWhitespace();
-                        reader.readEnd(SRU_NS, "recordData", true);
-
-                        String identifier = null;
-                        if (version == SRUVersion.VERSION_1_2) {
-                            identifier = reader.readContent(SRU_NS,
-                                    "recordIdentifier", false);
-                        }
-
-                        int position = reader.readContent(SRU_NS,
-                                "recordPosition", false, -1);
-
-                        logger.debug("recordIdentifier = {}, recordPosition = {}",
-                                identifier, position);
-
-                        // notify handler
-                        if (surrogate != null) {
-                            handler.onSurrogateRecord(identifier,
-                                    position, surrogate);
-                        } else {
-                            if (recordData != null) {
-                                handler.onRecord(identifier,
-                                        position, recordData);
-                            }
-                        }
-
-                        if (reader.readStart(SRU_NS, "extraRecordData", false)) {
-                            reader.consumeWhitespace();
-                            proxy.reset(reader);
-                            try {
-                                handler.onExtraRecordData(identifier,
-                                        position, proxy);
-                            } catch (XMLStreamException e) {
-                                throw new SRUClientException("handler "
-                                        + "triggered error while parsing "
-                                        + "'extraRecordData'", e);
-                            }
-                            reader.consumeWhitespace();
-                            reader.readEnd(SRU_NS, "extraRecordData", true);
-                        }
-
-                        reader.readEnd(SRU_NS, "record");
-                    } // while
-                    reader.readEnd(SRU_NS, "records");
+
+                            reader.readEnd(SRU_NS, "record");
+                            recordCount++;
+                        } // while
+                        reader.readEnd(SRU_NS, "records");
+                    }
+                    if (recordCount == 0) {
+                        logger.error("endpoint declared {} results, but response contained no <record> elements (behavior may violate SRU specification)", numberOfRecords);
+                    } else if ((request.getMaximumRecords() != -1) && (recordCount > request.getMaximumRecords())) {
+                        logger.error("endpoint did not honour 'maximumRecords' request parameter and responded with {} records instead of a maximum of {}", recordCount, request.getMaximumRecords());
+                    }
                 } else {
                     /*
-                     * provide a better error format, if
+                     * provide a better error format, if endpoints responds with
+                     * an empty <records> element
                      */
                     if (reader.readStart(SRU_NS, "records", false)) {
@@ -1000,5 +1165,5 @@
                         } else {
                             logger.error("endpoint declared 0 results, but " +
-                                    "response contained an " + bad +
+                                    "response contained " + bad +
                                     " record(s)");
                             if (strictMode) {
@@ -1108,5 +1273,5 @@
 
     private static SRUDiagnostic parseDiagnostic(SRUXMLStreamReader reader,
-            boolean required, boolean stictMode) throws XMLStreamException,
+            boolean required, boolean strictMode) throws XMLStreamException,
             SRUClientException {
         if (reader.readStart(SRU_DIAGNOSIC_NS, "diagnostic", required)) {
@@ -1115,19 +1280,45 @@
             String uri = reader.readContent(SRU_DIAGNOSIC_NS, "uri", true);
 
-            // diagnostic/details
-            String details = reader.readContent(SRU_DIAGNOSIC_NS, "details",
-                    false, stictMode);
+            String details = null;
+            String message = null;
+            if (strictMode) {
+                // diagnostic/details
+                details = reader.readContent(SRU_DIAGNOSIC_NS, "details",
+                        false, true);
+
+                // diagnostic/message
+                message = reader.readContent(SRU_DIAGNOSIC_NS, "message",
+                        false, true);
+            } else {
+                /*
+                 * common error: diagnostic/details and diagnostic/message may
+                 * appear in any order
+                 */
+                if (reader.peekStart(SRU_DIAGNOSIC_NS, "details")) {
+                    details = reader.readContent(SRU_DIAGNOSIC_NS, "details",
+                            false, false);
+                    message = reader.readContent(SRU_DIAGNOSIC_NS, "message",
+                            false, false);
+                } else {
+                    message = reader.readContent(SRU_DIAGNOSIC_NS, "message",
+                            false, false);
+                    details = reader.readContent(SRU_DIAGNOSIC_NS, "details",
+                            false, false);
+                    if ((message != null) && (details != null)) {
+                        logger.error("element <message> and element " +
+                                "<details> within element <diagnostic> " +
+                                "appeared in wrong order");
+                    }
+                }
+            }
+
             if ((details != null) && details.isEmpty()) {
                 details = null;
-                logger.warn("omitting empty element <details> " +
+                logger.debug("omitting empty element <details> " +
                         "within element <diagnostic>");
             }
-
-            // diagnostic/message
-            String message = reader.readContent(SRU_DIAGNOSIC_NS, "message",
-                    false, stictMode);
             if ((message != null) && message.isEmpty()) {
                 message = null;
-                logger.warn("omitting empty element <message> " +
+                logger.debug("omitting empty element <message> " +
                         "within element <diagnostic>");
             }
Index: SRUClient/trunk/src/main/java/eu/clarin/sru/client/SRUThreadedClient.java
===================================================================
--- SRUClient/trunk/src/main/java/eu/clarin/sru/client/SRUThreadedClient.java	(revision 2881)
+++ SRUClient/trunk/src/main/java/eu/clarin/sru/client/SRUThreadedClient.java	(revision 2936)
@@ -107,17 +107,14 @@
     /**
      * Register a record data parser.
-     *
+     * 
      * @param parser
      *            a parser instance
-     * @throws SRUClientException
-     *             if a parser handing the same record schema is already
-     *             registered
      * @throws NullPointerException
      *             if any required argument is <code>null</code>
      * @throws IllegalArgumentException
-     *             if the supplied parser is invalid
-     */
-    public void registerRecordParser(SRURecordDataParser parser)
-            throws SRUClientException {
+     *             if the supplied parser is invalid or a parser handing the
+     *             same record schema is already registered
+     */
+    public void registerRecordParser(SRURecordDataParser parser) {
         if (parser == null) {
             throw new NullPointerException("parser == null");
@@ -133,5 +130,5 @@
 
         if (parsers.putIfAbsent(recordSchema, parser) != null) {
-            throw new SRUClientException(
+            throw new IllegalArgumentException(
                     "record data parser already registered: " + recordSchema);
 
Index: SRUClient/trunk/src/main/java/eu/clarin/sru/client/XmlStreamReaderUtils.java
===================================================================
--- SRUClient/trunk/src/main/java/eu/clarin/sru/client/XmlStreamReaderUtils.java	(revision 2881)
+++ SRUClient/trunk/src/main/java/eu/clarin/sru/client/XmlStreamReaderUtils.java	(revision 2936)
@@ -32,5 +32,7 @@
     }
 
-    public static boolean readStart(XMLStreamReader reader, String namespaceURI, String localName, boolean required)
+
+    public static boolean readStart(XMLStreamReader reader,
+            String namespaceURI, String localName, boolean required)
             throws XMLStreamException {
         return readStart(reader, namespaceURI, localName, required, false);
@@ -38,5 +40,6 @@
 
 
-    public static boolean readStart(XMLStreamReader reader, String namespaceURI, String localName, boolean required,
+    public static boolean readStart(XMLStreamReader reader,
+            String namespaceURI, String localName, boolean required,
             boolean attributes) throws XMLStreamException {
         // System.err.println("readStart (" + localName + ", required = " +
@@ -80,12 +83,12 @@
 
 
-    public static void readEnd(XMLStreamReader reader, String namespaceURI, String localName)
-            throws XMLStreamException {
+    public static void readEnd(XMLStreamReader reader, String namespaceURI,
+            String localName) throws XMLStreamException {
         readEnd(reader, namespaceURI, localName, false);
     }
 
 
-    public static void readEnd(XMLStreamReader reader, String namespaceURI, String localName, boolean skipContent)
-            throws XMLStreamException {
+    public static void readEnd(XMLStreamReader reader, String namespaceURI,
+            String localName, boolean skipContent) throws XMLStreamException {
         // System.err.println("readEnd (" + localName + ") @ " + dumpState() +
         // ", skipContent = " + skipContent);
@@ -135,5 +138,6 @@
 
 
-    public static String readContent(XMLStreamReader reader, String namespaceURI, String localName, boolean required)
+    public static String readContent(XMLStreamReader reader,
+            String namespaceURI, String localName, boolean required)
             throws XMLStreamException {
         String result = null;
@@ -146,6 +150,7 @@
 
 
-    public static int readContent(XMLStreamReader reader, String namespaceURI, String localName, boolean required,
-            int defaultValue) throws XMLStreamException {
+    public static int readContent(XMLStreamReader reader, String namespaceURI,
+            String localName, boolean required, int defaultValue)
+            throws XMLStreamException {
         if (readStart(reader, namespaceURI, localName, required)) {
             String s = readString(reader, true);
@@ -162,5 +167,6 @@
 
 
-    public static String readString(XMLStreamReader reader, boolean required) throws XMLStreamException {
+    public static String readString(XMLStreamReader reader, boolean required)
+            throws XMLStreamException {
         // System.err.println("readString @ " + toReadable(reader));
         String s = null;
@@ -181,5 +187,6 @@
 
 
-    public static String readAttributeValue(XMLStreamReader reader, String namespaceURI, String localName)
+    public static String readAttributeValue(XMLStreamReader reader,
+            String namespaceURI, String localName, boolean required)
             throws XMLStreamException {
         if (!reader.isStartElement()) {
@@ -189,5 +196,13 @@
         String attr = reader.getAttributeValue(namespaceURI, localName);
         if (attr != null) {
-            attr = attr.trim().intern();
+            attr = attr.trim();
+            if (attr.isEmpty()) {
+                attr = null;
+            }
+        }
+        if ((attr == null) && required) {
+            throw new XMLStreamException("expected non-empty attribute '" +
+                    new QName(namespaceURI, localName) + "' on element '" +
+                    reader.getName() + "'", reader.getLocation());
         }
         return attr;
@@ -195,5 +210,12 @@
 
 
-    public static String readNamespaceURI(XMLStreamReader reader) throws XMLStreamException {
+    public static String readAttributeValue(XMLStreamReader reader,
+            String namespaceURI, String localName) throws XMLStreamException {
+        return readAttributeValue(reader, namespaceURI, localName, false);
+    }
+
+
+    public static String readNamespaceURI(XMLStreamReader reader)
+            throws XMLStreamException {
         if (!reader.isStartElement()) {
             throw new XMLStreamException("not at a start elment event",
@@ -204,5 +226,6 @@
 
 
-    public static String peekElementLocalName(XMLStreamReader reader) throws XMLStreamException {
+    public static String peekElementLocalName(XMLStreamReader reader)
+            throws XMLStreamException {
         if (!reader.isStartElement()) {
             throw new XMLStreamException("not at a start elment event",
@@ -213,5 +236,6 @@
 
 
-    public static void consumeStart(XMLStreamReader reader) throws XMLStreamException {
+    public static void consumeStart(XMLStreamReader reader)
+            throws XMLStreamException {
         if (!reader.isStartElement()) {
             throw new XMLStreamException("not at a start elment event",
@@ -222,5 +246,6 @@
 
 
-    public static void consumeWhitespace(XMLStreamReader reader) throws XMLStreamException {
+    public static void consumeWhitespace(XMLStreamReader reader)
+            throws XMLStreamException {
         while (reader.isWhiteSpace() && reader.hasNext()) {
             reader.next();
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 2881)
+++ SRUClient/trunk/src/main/java/eu/clarin/sru/client/fcs/ClarinFCSRecordParser.java	(revision 2936)
@@ -27,4 +27,5 @@
 import eu.clarin.sru.client.SRURecordData;
 import eu.clarin.sru.client.SRURecordDataParser;
+import eu.clarin.sru.client.SRUVersion;
 import eu.clarin.sru.client.XmlStreamReaderUtils;
 
@@ -53,5 +54,5 @@
 
     @Override
-    public SRURecordData parse(XMLStreamReader reader)
+    public SRURecordData parse(XMLStreamReader reader, SRUVersion version)
             throws XMLStreamException, SRUClientException {
         logger.debug("parsing CLARIN-FCS record");
Index: SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestClient.java
===================================================================
--- SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestClient.java	(revision 2881)
+++ SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestClient.java	(revision 2936)
@@ -33,10 +33,6 @@
             SRUClient client = new SRUClient();
 
-            try {
-                client.registerRecordParser(new ClarinFCSRecordParser());
-            } catch (SRUClientException e) {
-                logger.error("error adding record parser", e);
-                System.exit(1);
-            }
+            // register record data parsers
+            client.registerRecordParser(new ClarinFCSRecordParser());
 
             // 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 2881)
+++ SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestSimpleClient.java	(revision 2936)
@@ -33,11 +33,8 @@
         if (args.length > 0) {
             logger.info("initializing client ...");
-            SRUSimpleClient client = new SRUSimpleClient(SRUVersion.VERSION_1_2);
-            try {
-                client.registerRecordParser(new ClarinFCSRecordParser());
-            } catch (SRUClientException e) {
-                logger.error("error adding record parser", e);
-                System.exit(1);
-            }
+            SRUSimpleClient client = new SRUSimpleClient();
+
+            // register record data parsers
+            client.registerRecordParser(new ClarinFCSRecordParser());
 
             /*
@@ -110,4 +107,7 @@
                                 (ClarinFCSRecordData) data;
                         TestUtils.dumpResource(record.getResource());
+                    } else if (SRUExplainRecordData.RECORD_SCHEMA
+                            .equals(data.getRecordSchema())) {
+                        TestUtils.dumpExplainRecordData(data);
                     }
                 }
Index: SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestThreadedClient.java
===================================================================
--- SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestThreadedClient.java	(revision 2881)
+++ SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestThreadedClient.java	(revision 2936)
@@ -35,10 +35,6 @@
             SRUThreadedClient client = new SRUThreadedClient();
 
-            try {
-                client.registerRecordParser(new ClarinFCSRecordParser());
-            } catch (SRUClientException e) {
-                logger.error("error adding record parser", e);
-                System.exit(1);
-            }
+            // register record data parsers
+            client.registerRecordParser(new ClarinFCSRecordParser());
 
             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 2881)
+++ SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestThreadedClientCallback.java	(revision 2936)
@@ -34,10 +34,6 @@
             SRUThreadedClient client = new SRUThreadedClient();
 
-            try {
-                client.registerRecordParser(new ClarinFCSRecordParser());
-            } catch (SRUClientException e) {
-                logger.error("error adding record parser", e);
-                System.exit(1);
-            }
+            // register record data parsers
+            client.registerRecordParser(new ClarinFCSRecordParser());
 
             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 2881)
+++ SRUClient/trunk/src/test/java/eu/clarin/sru/client/TestUtils.java	(revision 2936)
@@ -42,5 +42,5 @@
     public static SRUScanRequest makeScanRequest(String baseURI) {
         SRUScanRequest request = new SRUScanRequest(baseURI);
-        request.setScanClause("fcs.resource");
+        request.setScanClause("fcs.resource = root");
         request.setExtraRequestData("x-clarin-resource-info", "true");
         return request;
@@ -75,4 +75,7 @@
             SRURecord record = response.getRecord();
             logger.info("schema = {}", record.getRecordSchema());
+            if (record.isRecordSchema(SRUExplainRecordData.RECORD_SCHEMA)) {
+                dumpExplainRecordData(record.getRecordData());
+            }
         }
     }
@@ -145,4 +148,17 @@
 
 
+    public static void dumpExplainRecordData(SRURecordData recordData) {
+        if (SRUExplainRecordData.RECORD_SCHEMA.equals(recordData.getRecordSchema())) {
+            SRUExplainRecordData data = (SRUExplainRecordData) recordData;
+            logger.info("host={}, port={}, database={}", new Object[] {
+                    data.getServerInfo().getHost(),
+                    data.getServerInfo().getPort(),
+                    data.getServerInfo().getDatabase()
+            });
+            
+        }
+    }
+
+
     public static void dumpResource(Resource resource) {
         logger.info("CLARIN-FCS: pid={}, ref={}",
