From ab58e1662c31d65ca2952cac469e05d20b47882d Mon Sep 17 00:00:00 2001
From: "Stefan E. Funk" <funk@sub.uni-goettingen.de>
Date: Mon, 25 Oct 2021 17:23:29 +0200
Subject: [PATCH] Fix restok bug Add tests for restok bug Increase version

---
 oaipmh-core/pom.xml                           |   2 +-
 .../IdentifierListDelivererAbstract.java      |  87 +--------
 .../IdentifierListDelivererDATACITE.java      |  75 ++++++-
 .../middleware/IdentifierListDelivererDC.java |  75 ++++++-
 .../IdentifierListDelivererIDIOM.java         |  12 +-
 .../IdentifierListDelivererInterface.java     |   6 +-
 .../info/textgrid/middleware/OAIPMHImpl.java  |  59 +++---
 .../textgrid/middleware/OAIPMHUtilities.java  |   5 -
 .../RecordListDelivererAbstract.java          | 184 +-----------------
 .../RecordListDelivererDATACITE.java          | 117 ++++++++++-
 .../middleware/RecordListDelivererDC.java     |   3 +
 .../middleware/RecordListDelivererIDIOM.java  |  16 +-
 .../middleware/OaiPmhTextgridOnlineTests.java |  84 ++++++--
 oaipmh-webapp/pom.xml                         |   2 +-
 pom.xml                                       |   2 +-
 15 files changed, 407 insertions(+), 322 deletions(-)

diff --git a/oaipmh-core/pom.xml b/oaipmh-core/pom.xml
index ec1fecad..6c9ab177 100644
--- a/oaipmh-core/pom.xml
+++ b/oaipmh-core/pom.xml
@@ -5,7 +5,7 @@
 	<parent>
 		<artifactId>oaipmh</artifactId>
 		<groupId>info.textgrid.middleware</groupId>
-		<version>4.0.5-SNAPSHOT</version>
+		<version>4.0.6-SNAPSHOT</version>
 	</parent>
 	<groupId>info.textgrid.middleware</groupId>
 	<artifactId>oaipmh-core</artifactId>
diff --git a/oaipmh-core/src/main/java/info/textgrid/middleware/IdentifierListDelivererAbstract.java b/oaipmh-core/src/main/java/info/textgrid/middleware/IdentifierListDelivererAbstract.java
index 0bcf0fc0..a3229fe4 100644
--- a/oaipmh-core/src/main/java/info/textgrid/middleware/IdentifierListDelivererAbstract.java
+++ b/oaipmh-core/src/main/java/info/textgrid/middleware/IdentifierListDelivererAbstract.java
@@ -1,24 +1,15 @@
 package info.textgrid.middleware;
 
-import java.io.IOException;
 import java.text.ParseException;
 import java.util.ArrayList;
-import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
 import javax.xml.datatype.DatatypeConfigurationException;
 import org.apache.commons.logging.LogFactory;
-import org.elasticsearch.action.search.SearchRequest;
 import org.elasticsearch.action.search.SearchResponse;
-import org.elasticsearch.action.search.SearchScrollRequest;
-import org.elasticsearch.action.search.SearchType;
-import org.elasticsearch.client.RequestOptions;
-import org.elasticsearch.common.Strings;
-import org.elasticsearch.common.unit.TimeValue;
 import org.elasticsearch.index.query.QueryBuilder;
 import org.elasticsearch.index.query.QueryBuilders;
 import org.elasticsearch.search.SearchHit;
-import org.elasticsearch.search.builder.SearchSourceBuilder;
 import org.json.JSONObject;
 import info.textgrid.middleware.oaipmh.HeaderType;
 import info.textgrid.middleware.oaipmh.ListIdentifiersType;
@@ -42,7 +33,6 @@ public abstract class IdentifierListDelivererAbstract implements IdentifierListD
 
   private static org.apache.commons.logging.Log log =
       LogFactory.getLog(RecordListDelivererAbstract.class);
-  protected static Map<String, Integer> cursorCollector = new Hashtable<String, Integer>();
 
   // **
   // CLASS
@@ -92,6 +82,7 @@ public abstract class IdentifierListDelivererAbstract implements IdentifierListD
     if (request.getMetadataPrefix() != null && request.getResumptionToken() != null) {
       result.setError(OAIPMHConstants.OAI_BAD_ARGUMENT,
           "The resumptionToken is an exclusive argument, please remove metadataPrefix!");
+      return result;
     }
 
     // Check if metadata prefix is existing and valid.
@@ -103,23 +94,10 @@ public abstract class IdentifierListDelivererAbstract implements IdentifierListD
           "The value of the metadataPrefix " + request.getMetadataPrefix()
               + " is not supported by the item identified by the value of: "
               + request.getIdentifier());
+      return result;
     }
 
-    // Check for invalid resumptionToken.
-    if (request.getResumptionToken() != null) {
-      boolean restokDCExisting = IdentifierListDelivererDC.cursorCollector != null
-          && IdentifierListDelivererDC.cursorCollector.containsKey(request.getResumptionToken());
-      boolean restokIDIOMExisting = IdentifierListDelivererIDIOM.cursorCollector != null
-          && IdentifierListDelivererDC.cursorCollector.containsKey(request.getResumptionToken());
-      boolean restok = cursorCollector != null
-          && cursorCollector.containsKey(request.getResumptionToken());
-      if (!restokDCExisting && !restokIDIOMExisting && !restok) {
-        result.setError(OAIPMHConstants.OAI_BAD_RESUMPTION_TOKEN, "The value of the "
-            + request.getResumptionToken() + " argument is invalid or expired.");
-      }
-    }
-
-    // Check more errors.
+    // Check params in general.
     List<String> errorValues = new ArrayList<String>();
 
     if (request.getResumptionToken() == null && request.getMetadataPrefix() == null) {
@@ -137,71 +115,16 @@ public abstract class IdentifierListDelivererAbstract implements IdentifierListD
     return result;
   }
 
-  /**
-   * <p>
-   * To get the required values for the ListIdentifiers request this function will ask ElasticSearch
-   * for a specific textgridUri the values "created" and "textgridUri".
-   * </p>
-   * 
-   * <p>
-   * Since the ListIdentifiers request enables the possibility the limit the request in a specific
-   * time interval, it is necessary to perform a range query on the ElasticSearch index.</p
-   * 
-   * @param from : start value for the range query
-   * @param to : end value to the range query
-   * @return after calling the function "setListIdentifierHeader" the return value is the whole
-   *         ListIdentifiers element
-   * @throws IOException
-   */
-  public ListIdentifiersType processIdentifierList(String from, String to, String set,
-      String resumptionToken) throws IOException, ParseException {
-
-    // FIXME combine it with with getIdentifierListWithSet and check for empty set
-
-    ListIdentifiersType lit = new ListIdentifiersType();
-    QueryBuilder query = setOrNot(set, from, to);
-    SearchResponse listListIdentiferValues;
-
-    String[] includes = this.identifierListFields;
-    String[] excludes = Strings.EMPTY_ARRAY;
-    // TODO: necessary?
-    // FetchSourceContext fetchSourceContext = new FetchSourceContext(true, includes, excludes);
-
-    SearchRequest searchRequest =
-        new SearchRequest(OAI_ESClient.getEsIndex()).searchType(SearchType.QUERY_THEN_FETCH);
-
-    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
-    searchSourceBuilder.query(query);
-    searchSourceBuilder.size(this.searchResponseSize);
-    searchSourceBuilder.fetchSource(includes, excludes);
-
-    if (resumptionToken != null) {
-      SearchScrollRequest scrollRequest = new SearchScrollRequest(resumptionToken);
-      scrollRequest.scroll(TimeValue.timeValueSeconds(lifeTimeResToken));
-      listListIdentiferValues =
-          OAI_ESClient.getEsClient().scroll(scrollRequest, RequestOptions.DEFAULT);
-    } else {
-      searchRequest.source(searchSourceBuilder);
-      searchRequest.scroll(TimeValue.timeValueMinutes(lifeTimeResToken));
-      listListIdentiferValues =
-          OAI_ESClient.getEsClient().search(searchRequest, RequestOptions.DEFAULT);
-    }
-
-    listListIdentiferValues =
-        hitHandling(listListIdentiferValues, lit, set, listListIdentiferValues.getScrollId());
-
-    return lit;
-  }
-
   /**
    * @param listFurtherValues
    * @param lit
    * @param set
    * @param resumptionToken
+   * @param cursorCollector
    * @return
    */
   public SearchResponse hitHandling(SearchResponse listFurtherValues, ListIdentifiersType lit,
-      String set, String resumptionToken) {
+      String set, String resumptionToken, Map<String, Integer> cursorCollector) {
 
     int i = 0;
     long size = listFurtherValues.getHits().totalHits;
diff --git a/oaipmh-core/src/main/java/info/textgrid/middleware/IdentifierListDelivererDATACITE.java b/oaipmh-core/src/main/java/info/textgrid/middleware/IdentifierListDelivererDATACITE.java
index ea7a7535..c19b2162 100644
--- a/oaipmh-core/src/main/java/info/textgrid/middleware/IdentifierListDelivererDATACITE.java
+++ b/oaipmh-core/src/main/java/info/textgrid/middleware/IdentifierListDelivererDATACITE.java
@@ -1,17 +1,34 @@
 package info.textgrid.middleware;
 
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.Hashtable;
+import java.util.Map;
+import org.elasticsearch.action.search.SearchRequest;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.action.search.SearchScrollRequest;
+import org.elasticsearch.action.search.SearchType;
+import org.elasticsearch.client.RequestOptions;
+import org.elasticsearch.common.Strings;
+import org.elasticsearch.common.unit.TimeValue;
+import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.search.builder.SearchSourceBuilder;
+import info.textgrid.middleware.oaipmh.ListIdentifiersType;
+
 /**
  * <p>
  * Class to build the Element for a ListIdentifiers request.
  * </p>
  * 
  * @author Stefan E. Funk, SUB Göttingen
- * @version 2021-07-06
+ * @version 2021-10-25
  * @since 2014-02-20
  */
 
 public class IdentifierListDelivererDATACITE extends IdentifierListDelivererAbstract {
 
+  protected static Map<String, Integer> cursorCollector = new Hashtable<String, Integer>();
+
   /**
    * @param datestamp taken from the elasticSearch index (created element)
    * @param identifier taken from the elasticSearch index (textgridUri)
@@ -21,4 +38,60 @@ public class IdentifierListDelivererDATACITE extends IdentifierListDelivererAbst
     super(textgrid, dariah);
   }
 
+  /*
+   * (non-Javadoc)
+   * 
+   * @see info.textgrid.middleware.IdentifierListDelivererInterface#processIdentifierList(java.lang.
+   * String, java.lang.String, java.lang.String, java.lang.String)
+   */
+  public ListIdentifiersType processIdentifierList(String from, String to, String set,
+      String resumptionToken) throws IOException, ParseException {
+
+    /*
+     * To get the required values for the ListIdentifiers request this function will ask
+     * ElasticSearc for a specific textgridUri the values "created" and "textgridUri".
+     */
+
+    /*
+     * Since the ListIdentifiers request enables the possibility the limit the request in a specific
+     * time interval, it is necessary to perform a range query on the ElasticSearch index.
+     */
+
+    // FIXME combine it with with getIdentifierListWithSet and check for empty set
+
+    ListIdentifiersType lit = new ListIdentifiersType();
+    QueryBuilder query = setOrNot(set, from, to);
+    SearchResponse listListIdentiferValues;
+
+    String[] includes = this.identifierListFields;
+    String[] excludes = Strings.EMPTY_ARRAY;
+    // TODO: necessary?
+    // FetchSourceContext fetchSourceContext = new FetchSourceContext(true, includes, excludes);
+
+    SearchRequest searchRequest =
+        new SearchRequest(OAI_ESClient.getEsIndex()).searchType(SearchType.QUERY_THEN_FETCH);
+
+    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
+    searchSourceBuilder.query(query);
+    searchSourceBuilder.size(this.searchResponseSize);
+    searchSourceBuilder.fetchSource(includes, excludes);
+
+    if (resumptionToken != null) {
+      SearchScrollRequest scrollRequest = new SearchScrollRequest(resumptionToken);
+      scrollRequest.scroll(TimeValue.timeValueSeconds(lifeTimeResToken));
+      listListIdentiferValues =
+          OAI_ESClient.getEsClient().scroll(scrollRequest, RequestOptions.DEFAULT);
+    } else {
+      searchRequest.source(searchSourceBuilder);
+      searchRequest.scroll(TimeValue.timeValueMinutes(lifeTimeResToken));
+      listListIdentiferValues =
+          OAI_ESClient.getEsClient().search(searchRequest, RequestOptions.DEFAULT);
+    }
+
+    listListIdentiferValues = hitHandling(listListIdentiferValues, lit, set,
+        listListIdentiferValues.getScrollId(), cursorCollector);
+
+    return lit;
+  }
+
 }
diff --git a/oaipmh-core/src/main/java/info/textgrid/middleware/IdentifierListDelivererDC.java b/oaipmh-core/src/main/java/info/textgrid/middleware/IdentifierListDelivererDC.java
index 6aad6aaa..483bdef8 100644
--- a/oaipmh-core/src/main/java/info/textgrid/middleware/IdentifierListDelivererDC.java
+++ b/oaipmh-core/src/main/java/info/textgrid/middleware/IdentifierListDelivererDC.java
@@ -1,5 +1,20 @@
 package info.textgrid.middleware;
 
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.Hashtable;
+import java.util.Map;
+import org.elasticsearch.action.search.SearchRequest;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.action.search.SearchScrollRequest;
+import org.elasticsearch.action.search.SearchType;
+import org.elasticsearch.client.RequestOptions;
+import org.elasticsearch.common.Strings;
+import org.elasticsearch.common.unit.TimeValue;
+import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.search.builder.SearchSourceBuilder;
+import info.textgrid.middleware.oaipmh.ListIdentifiersType;
+
 /**
  * <p>
  * Class to build the Element for a ListIdentifiers request.
@@ -7,12 +22,14 @@ package info.textgrid.middleware;
  * 
  * @author Maximilian Brodhun, SUB Göttingen
  * @author Stefan E. Funk, SUB Göttingen
- * @version 2021-07-06
+ * @version 2021-10-25
  * @since 2014-02-20
  */
 
 public class IdentifierListDelivererDC extends IdentifierListDelivererAbstract {
 
+  protected static Map<String, Integer> cursorCollector = new Hashtable<String, Integer>();
+
   /**
    * <p>
    * In OAIPMH a ListIdentifiers request is answered by responding the datestamp and the identifier
@@ -28,4 +45,60 @@ public class IdentifierListDelivererDC extends IdentifierListDelivererAbstract {
     super(textgrid, dariah);
   }
 
+  /*
+   * (non-Javadoc)
+   * 
+   * @see info.textgrid.middleware.IdentifierListDelivererInterface#processIdentifierList(java.lang.
+   * String, java.lang.String, java.lang.String, java.lang.String)
+   */
+  public ListIdentifiersType processIdentifierList(String from, String to, String set,
+      String resumptionToken) throws IOException, ParseException {
+
+    /*
+     * To get the required values for the ListIdentifiers request this function will ask
+     * ElasticSearc for a specific textgridUri the values "created" and "textgridUri".
+     */
+
+    /*
+     * Since the ListIdentifiers request enables the possibility the limit the request in a specific
+     * time interval, it is necessary to perform a range query on the ElasticSearch index.
+     */
+
+    // FIXME combine it with with getIdentifierListWithSet and check for empty set
+
+    ListIdentifiersType lit = new ListIdentifiersType();
+    QueryBuilder query = setOrNot(set, from, to);
+    SearchResponse listListIdentiferValues;
+
+    String[] includes = this.identifierListFields;
+    String[] excludes = Strings.EMPTY_ARRAY;
+    // TODO: necessary?
+    // FetchSourceContext fetchSourceContext = new FetchSourceContext(true, includes, excludes);
+
+    SearchRequest searchRequest =
+        new SearchRequest(OAI_ESClient.getEsIndex()).searchType(SearchType.QUERY_THEN_FETCH);
+
+    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
+    searchSourceBuilder.query(query);
+    searchSourceBuilder.size(this.searchResponseSize);
+    searchSourceBuilder.fetchSource(includes, excludes);
+
+    if (resumptionToken != null) {
+      SearchScrollRequest scrollRequest = new SearchScrollRequest(resumptionToken);
+      scrollRequest.scroll(TimeValue.timeValueSeconds(lifeTimeResToken));
+      listListIdentiferValues =
+          OAI_ESClient.getEsClient().scroll(scrollRequest, RequestOptions.DEFAULT);
+    } else {
+      searchRequest.source(searchSourceBuilder);
+      searchRequest.scroll(TimeValue.timeValueMinutes(lifeTimeResToken));
+      listListIdentiferValues =
+          OAI_ESClient.getEsClient().search(searchRequest, RequestOptions.DEFAULT);
+    }
+
+    listListIdentiferValues = hitHandling(listListIdentiferValues, lit, set,
+        listListIdentiferValues.getScrollId(), cursorCollector);
+
+    return lit;
+  }
+
 }
diff --git a/oaipmh-core/src/main/java/info/textgrid/middleware/IdentifierListDelivererIDIOM.java b/oaipmh-core/src/main/java/info/textgrid/middleware/IdentifierListDelivererIDIOM.java
index 2da5475f..e7256c83 100644
--- a/oaipmh-core/src/main/java/info/textgrid/middleware/IdentifierListDelivererIDIOM.java
+++ b/oaipmh-core/src/main/java/info/textgrid/middleware/IdentifierListDelivererIDIOM.java
@@ -2,6 +2,8 @@ package info.textgrid.middleware;
 
 import java.io.IOException;
 import java.text.ParseException;
+import java.util.Hashtable;
+import java.util.Map;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.elasticsearch.action.search.SearchRequest;
@@ -23,7 +25,16 @@ import info.textgrid.middleware.oaipmh.ResumptionTokenType;
  */
 public class IdentifierListDelivererIDIOM extends IdentifierListDelivererAbstract {
 
+  // **
+  // STATICS
+  // **
+
   private static Log log = LogFactory.getLog(IdentifierListDelivererIDIOM.class);
+  protected static Map<String, Integer> cursorCollector = new Hashtable<String, Integer>();
+
+  // **
+  // CLASS
+  // **
 
   // Set default to 30, can be changed in oaipmh.properties.
   private int idiomResponseSize = 30;
@@ -60,7 +71,6 @@ public class IdentifierListDelivererIDIOM extends IdentifierListDelivererAbstrac
         .must(QueryBuilders.matchPhraseQuery("format", "text/tg.inputform+rdf+xml"))
         .must(QueryBuilders.matchPhraseQuery("notes", "ARTEFACT"));
 
-
     // List<String> artefactURIs = new ArrayList<String>();
     // Queries queries = new Queries();
 
diff --git a/oaipmh-core/src/main/java/info/textgrid/middleware/IdentifierListDelivererInterface.java b/oaipmh-core/src/main/java/info/textgrid/middleware/IdentifierListDelivererInterface.java
index 81068740..3c0a2020 100644
--- a/oaipmh-core/src/main/java/info/textgrid/middleware/IdentifierListDelivererInterface.java
+++ b/oaipmh-core/src/main/java/info/textgrid/middleware/IdentifierListDelivererInterface.java
@@ -10,13 +10,13 @@ import info.textgrid.middleware.oaipmh.ListIdentifiersType;
 public interface IdentifierListDelivererInterface {
 
   /**
-   * @param from
-   * @param to
+   * @param from Start value for the range query
+   * @param to End value to the range query
    * @param set
    * @param resumptionToken
    * @return
    * @throws ParseException
- * @throws IOException 
+   * @throws IOException
    */
   public ListIdentifiersType processIdentifierList(String from, String to, String set,
       String resumptionToken) throws ParseException, IOException;
diff --git a/oaipmh-core/src/main/java/info/textgrid/middleware/OAIPMHImpl.java b/oaipmh-core/src/main/java/info/textgrid/middleware/OAIPMHImpl.java
index aa3a0a98..28e4e5b8 100644
--- a/oaipmh-core/src/main/java/info/textgrid/middleware/OAIPMHImpl.java
+++ b/oaipmh-core/src/main/java/info/textgrid/middleware/OAIPMHImpl.java
@@ -32,7 +32,7 @@ import info.textgrid.middleware.oaipmh.VerbType;
  * 
  * @author Maximilian Brodhun, SUB Göttingen
  * @author Stefan E. Funk, SUB Göttingen
- * @version 2021-10-21
+ * @version 2021-10-25
  * @since 2014-01-29
  */
 public class OAIPMHImpl implements OAIPMHProducer {
@@ -347,8 +347,7 @@ public class OAIPMHImpl implements OAIPMHProducer {
 
       IdentifierListDelivererInterface idListDeliv = null;
 
-      // If metadataFormat IS SET, set recordListDeliverer accordingly (requestChecker checks for
-      // BOTH resumption token and metadata format params!).
+      // If metadataFormat IS SET, set recordListDeliverer accordingly.
       if (request.getMetadataPrefix() != null) {
         if (request.getMetadataPrefix().equals(OAIPMHUtilities.OAIDC_PREFIX)) {
           idListDeliv = this.identifierListDC;
@@ -359,25 +358,33 @@ public class OAIPMHImpl implements OAIPMHProducer {
         }
       }
 
-      // If resumption token IS SET, check resumption token hash maps to decide which metadata
+      // If metadata prefix is NOT set, check resumption token hash maps to decide which metadata
       // format we shall use.
       else {
-        boolean restokDCExisting = IdentifierListDelivererDC.cursorCollector != null
-            && IdentifierListDelivererDC.cursorCollector.containsKey(request.getResumptionToken());
-        boolean restokIDIOMExisting = IdentifierListDelivererIDIOM.cursorCollector != null
-            && IdentifierListDelivererIDIOM.cursorCollector
-                .containsKey(request.getResumptionToken());
-        // FIXME KWAKK!!
-        boolean restokOpenAireExisting = OAIPMHUtilities.cursorCollector != null
-            && IdentifierListDelivererAbstract.cursorCollector
+        boolean restokDCExisting = RecordListDelivererDC.cursorCollector != null
+            && RecordListDelivererDC.cursorCollector.containsKey(request.getResumptionToken());
+        boolean restokIDIOMExisting = RecordListDelivererIDIOM.cursorCollector != null
+            && RecordListDelivererIDIOM.cursorCollector.containsKey(request.getResumptionToken());
+        boolean restokOpenAireExisting = RecordListDelivererDATACITE.cursorCollector != null
+            && RecordListDelivererDATACITE.cursorCollector
                 .containsKey(request.getResumptionToken());
 
+        this.log.info("restokDCExisting " + restokDCExisting);
+        this.log.info("restokIDIOMExisting " + restokIDIOMExisting);
+        this.log.info("restokOpenAireExisting " + restokOpenAireExisting);
+
         if (restokDCExisting) {
           idListDeliv = this.identifierListDC;
         } else if (restokIDIOMExisting) {
           idListDeliv = this.identifierListIDIOM;
         } else if (restokOpenAireExisting) {
           idListDeliv = this.identifierListDATACITE;
+        } else {
+          // We have got an invalid resumptionToken here!
+          ErrorHandler e = new ErrorHandler();
+          e.setError(OAIPMHConstants.OAI_BAD_RESUMPTION_TOKEN, "The value of the "
+              + request.getResumptionToken() + " argument is invalid or expired.");
+          oaipmhRoot.getError().add(e.getError());
         }
       }
 
@@ -527,8 +534,7 @@ public class OAIPMHImpl implements OAIPMHProducer {
 
       RecordListDelivererInterface recListDeliv = null;
 
-      // If metadataFormat IS SET, set recordListDeliverer accordingly (requestChecker checks for
-      // BOTH resumption token and metadata format params!).
+      // If metadataFormat IS SET, set recordListDeliverer accordingly.
       if (request.getMetadataPrefix() != null) {
         if (request.getMetadataPrefix().equals(OAIPMHUtilities.OAIDC_PREFIX)) {
           recListDeliv = this.recordListDC;
@@ -541,28 +547,17 @@ public class OAIPMHImpl implements OAIPMHProducer {
         }
       }
 
-      // If resumption token IS SET, check resumption token hash maps to decide which metadata
+      // If metadata prefix is NOT set, check resumption token hash maps to decide which metadata
       // format we shall use.
       else {
         boolean restokDCExisting = RecordListDelivererDC.cursorCollector != null
             && RecordListDelivererDC.cursorCollector.containsKey(request.getResumptionToken());
-
-        this.log.info("restok DC: " + request.getResumptionToken());
-        this.log.info(RecordListDelivererDC.cursorCollector.entrySet());
-
         boolean restokIDIOMExisting = RecordListDelivererIDIOM.cursorCollector != null
             && RecordListDelivererIDIOM.cursorCollector.containsKey(request.getResumptionToken());
-
-        this.log.info("restok IDIOM: " + request.getResumptionToken());
-        this.log.info(RecordListDelivererIDIOM.cursorCollector.entrySet());
-
         boolean restokOpenAireExisting = RecordListDelivererDATACITE.cursorCollector != null
             && RecordListDelivererDATACITE.cursorCollector
                 .containsKey(request.getResumptionToken());
 
-        this.log.info("restok DATACITE: " + request.getResumptionToken());
-        this.log.info(RecordListDelivererDATACITE.cursorCollector.entrySet());
-
         this.log.info("restokDCExisting " + restokDCExisting);
         this.log.info("restokIDIOMExisting " + restokIDIOMExisting);
         this.log.info("restokOpenAireExisting " + restokOpenAireExisting);
@@ -573,6 +568,12 @@ public class OAIPMHImpl implements OAIPMHProducer {
           recListDeliv = this.recordListIDIOM;
         } else if (restokOpenAireExisting) {
           recListDeliv = this.recordListDATACITE;
+        } else {
+          // We have got an invalid resumptionToken here!
+          ErrorHandler e = new ErrorHandler();
+          e.setError(OAIPMHConstants.OAI_BAD_RESUMPTION_TOKEN, "The value of the "
+              + request.getResumptionToken() + " argument is invalid or expired.");
+          oaipmhRoot.getError().add(e.getError());
         }
       }
 
@@ -583,13 +584,7 @@ public class OAIPMHImpl implements OAIPMHProducer {
           request.getResumptionToken());
 
       if (listRecords != null) {
-        /*
-         * if (this.recordListDC.getResultSize() == 0) { requestErrors.setError("RecordMatchError",
-         * "The combination of the values of the from, until, set and metadataPrefix arguments results in an empty list."
-         * ); oaipmhRoot.getError().add(requestErrors.getError()); } else {
-         */
         oaipmhRoot.setListRecords(listRecords);
-        // }
       }
     }
 
diff --git a/oaipmh-core/src/main/java/info/textgrid/middleware/OAIPMHUtilities.java b/oaipmh-core/src/main/java/info/textgrid/middleware/OAIPMHUtilities.java
index 58b3b273..16daea53 100644
--- a/oaipmh-core/src/main/java/info/textgrid/middleware/OAIPMHUtilities.java
+++ b/oaipmh-core/src/main/java/info/textgrid/middleware/OAIPMHUtilities.java
@@ -10,7 +10,6 @@ import java.util.Arrays;
 import java.util.Date;
 import java.util.GregorianCalendar;
 import java.util.HashSet;
-import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
@@ -112,10 +111,6 @@ public class OAIPMHUtilities {
   // STATICS
   // **
 
-  protected static Map<String, Integer> cursorCollector = new Hashtable<String, Integer>();
-
-  // private static org.apache.commons.logging.Log log = LogFactory.getLog(OAIPMHImpl.class);
-
   /**
    * @param verb
    * @return
diff --git a/oaipmh-core/src/main/java/info/textgrid/middleware/RecordListDelivererAbstract.java b/oaipmh-core/src/main/java/info/textgrid/middleware/RecordListDelivererAbstract.java
index 87f51047..ed10a015 100644
--- a/oaipmh-core/src/main/java/info/textgrid/middleware/RecordListDelivererAbstract.java
+++ b/oaipmh-core/src/main/java/info/textgrid/middleware/RecordListDelivererAbstract.java
@@ -1,26 +1,15 @@
 package info.textgrid.middleware;
 
-import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Hashtable;
 import java.util.List;
-import java.util.Map;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.elasticsearch.action.search.SearchRequest;
-import org.elasticsearch.action.search.SearchResponse;
-import org.elasticsearch.action.search.SearchScrollRequest;
-import org.elasticsearch.client.RequestOptions;
-import org.elasticsearch.common.unit.TimeValue;
-import org.elasticsearch.index.query.QueryBuilder;
-import org.elasticsearch.index.query.QueryBuilders;
-import org.elasticsearch.search.SearchHit;
-import org.elasticsearch.search.builder.SearchSourceBuilder;
 import info.textgrid.middleware.oaipmh.RequestType;
 import info.textgrid.middleware.oaipmh.ResumptionTokenType;
 
 /**
- *
+ * @author Maximilian Brodhun, SUB Göttingen
+ * @author Stefan E. Funk, SUB Göttingen
+ * @version 2021-10-25
+ * @since
  */
 public abstract class RecordListDelivererAbstract implements RecordListDelivererInterface {
 
@@ -50,11 +39,6 @@ public abstract class RecordListDelivererAbstract implements RecordListDeliverer
 
   public ResumptionTokenType resTokenForResponse;
 
-  // private static final int LIFETIME_RES_TOKEN = 600;
-  protected static Map<String, Integer> cursorCollector = new Hashtable<String, Integer>();
-
-  private static Log log = LogFactory.getLog(RecordListDelivererAbstract.class);
-
   /**
    * @param textgrid
    * @param dariah
@@ -64,108 +48,6 @@ public abstract class RecordListDelivererAbstract implements RecordListDeliverer
     this.dariah = dariah;
   }
 
-  /**
-   * @param query
-   * @param resumptionToken
-   * @param set
-   * @return
-   */
-  protected List<String> getFieldsFromESIndex(QueryBuilder query, String resumptionToken,
-      String set) {
-
-    List<String> uriList = new ArrayList<String>();
-
-    QueryBuilder recordFilter;
-    if (this.textgrid) {
-      // We filter out all editions here!
-      recordFilter = QueryBuilders.boolQuery().must(query)
-          .must(QueryBuilders.matchPhraseQuery("format", this.formatToFilter));
-    } else {
-      // Do not filter at all in DH. We need every ID!
-      recordFilter = QueryBuilders.boolQuery().must(query);
-    }
-
-    SearchRequest searchRequest = new SearchRequest(OAI_ESClient.getEsIndex());
-    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
-
-    searchSourceBuilder.query(recordFilter);
-    searchSourceBuilder.size(this.searchResponseSize);
-    searchRequest.source(searchSourceBuilder);
-
-    SearchResponse scrollResp = new SearchResponse();
-
-    if (resumptionToken != null) {
-      SearchScrollRequest scrollRequest = new SearchScrollRequest(resumptionToken);
-      scrollRequest.scroll(TimeValue.timeValueHours(24L));
-
-      try {
-        scrollResp = OAI_ESClient.getEsClient().scroll(scrollRequest, RequestOptions.DEFAULT);
-      } catch (IOException e) {
-        // TODO Auto-generated catch block
-        e.printStackTrace();
-      }
-    } else {
-      searchRequest.source(searchSourceBuilder);
-      searchRequest.scroll(TimeValue.timeValueHours(24L));
-      try {
-        scrollResp = OAI_ESClient.getEsClient().search(searchRequest, RequestOptions.DEFAULT);
-      } catch (IOException e) {
-        // TODO Auto-generated catch block
-        e.printStackTrace();
-      }
-    }
-
-    String scrollID = scrollResp.getScrollId();
-    long completeListSize = scrollResp.getHits().totalHits;
-    setResultSize(completeListSize);
-
-    if (completeListSize > 0) {
-
-      setFoundItems(true);
-      int i = 0;
-
-      for (SearchHit hit : scrollResp.getHits().getHits()) {
-        i++;
-        if (hit != null && hit.getFields() != null) {
-          String id2add;
-          // FIXME Could we not use hit.getId() also for TG hits? Where is the difference?
-          if (this.textgrid) {
-            id2add = hit.getSourceAsMap().get(TGConstants.URI).toString();
-          } else {
-            id2add = hit.getId();
-          }
-          uriList.add(id2add);
-        }
-      }
-      if (resumptionToken != null
-          && this.resTokenForResponse.getCursor().intValue() >= completeListSize) {
-        try {
-          cursorCollector.remove(resumptionToken);
-        } catch (NullPointerException couldNotRemove) {
-          log.info("Could not remove hash value: " + resumptionToken + " from hash map");
-        }
-        this.resTokenForResponse.setValue("");
-      } else {
-        this.resTokenForResponse = OAIPMHUtilities.getResumptionToken(
-            completeListSize, resumptionToken, cursorCollector, scrollID, this.searchResponseSize,
-            i);
-      }
-
-      log.debug("cursorCollector: " + cursorCollector);
-
-    } else {
-      log.info("HALLO");
-      setFoundItems(false);
-    }
-
-    if (this.resTokenForResponse != null) {
-      log.debug("restok value: " + this.resTokenForResponse.getValue());
-      log.debug("restok cursor: " + this.resTokenForResponse.getCursor());
-    }
-
-    return uriList;
-  }
-
   /**
    * @param request
    * @return
@@ -175,10 +57,10 @@ public abstract class RecordListDelivererAbstract implements RecordListDeliverer
     ErrorHandler result = new ErrorHandler();
 
     // Check for metadata prefix AND resumption token.
-    // FIXME Doesn't work yet!!
     if (request.getMetadataPrefix() != null && request.getResumptionToken() != null) {
       result.setError(OAIPMHConstants.OAI_BAD_ARGUMENT,
           "The resumptionToken is an exclusive argument, please remove metadataPrefix!");
+      return result;
     }
 
     // Check if metadata prefix is existing and valid.
@@ -190,20 +72,7 @@ public abstract class RecordListDelivererAbstract implements RecordListDeliverer
           "The value of the metadataPrefix " + request.getMetadataPrefix()
               + " is not supported by the item identified by the value of: "
               + request.getIdentifier());
-    }
-
-    // Check for invalid resumptionToken.
-    if (request.getResumptionToken() != null) {
-      boolean restokIDIOMExisting = RecordListDelivererIDIOM.cursorCollector != null
-          && RecordListDelivererIDIOM.cursorCollector.containsKey(request.getResumptionToken());
-      boolean restokDCExisting = RecordListDelivererDC.cursorCollector != null
-          && RecordListDelivererDC.cursorCollector.containsKey(request.getResumptionToken());
-      boolean restok = cursorCollector != null
-          && cursorCollector.containsKey(request.getResumptionToken());
-      if (!restokDCExisting && !restokIDIOMExisting && !restok) {
-        result.setError(OAIPMHConstants.OAI_BAD_RESUMPTION_TOKEN, "The value of the "
-            + request.getResumptionToken() + " argument is invalid or expired.");
-      }
+      return result;
     }
 
     // Check params in general.
@@ -233,47 +102,6 @@ public abstract class RecordListDelivererAbstract implements RecordListDeliverer
     return result;
   }
 
-  // /*
-  // * (non-Javadoc)
-  // *
-  // * @see info.textgrid.middleware.RecordListDelivererInterface#setHeader(java.lang.String,
-  // * java.lang.String, java.lang.String)
-  // */
-  // public HeaderType setHeader(final String set, final String headerIdentifier,
-  // String modifiedDate) {
-  //
-  // HeaderType header = new HeaderType();
-  // String identifierForHeader = headerIdentifier;
-  //
-  // System.out.println("header identifier: " + headerIdentifier);
-  // System.out.println("modified value: " + modifiedDate);
-  //
-  // // Set date in XML format.
-  // try {
-  // header.setDatestamp(OAIPMHUtilities.convertDateFormat(modifiedDate).toXMLFormat());
-  // } catch (ParseException e) {
-  // // TODO Auto-generated catch block
-  // e.printStackTrace();
-  // } catch (DatatypeConfigurationException e) {
-  // // TODO Auto-generated catch block
-  // e.printStackTrace();
-  // }
-  //
-  // // Set header specific for TextGrid objects (remove URL).
-  // if (this.textgrid == true) {
-  // identifierForHeader = identifierForHeader.replaceFirst("https://textgridrep.org/", "");
-  // }
-  //
-  // header.setIdentifier(identifierForHeader);
-  //
-  // // Set set :-)
-  // if (set != null) {
-  // header.getSetSpec().add(this.specFieldPrefix + set);
-  // }
-  //
-  // return header;
-  // }
-
   // **
   // GETTER AND SETTER
   // **
diff --git a/oaipmh-core/src/main/java/info/textgrid/middleware/RecordListDelivererDATACITE.java b/oaipmh-core/src/main/java/info/textgrid/middleware/RecordListDelivererDATACITE.java
index e1b396a1..b9978d43 100644
--- a/oaipmh-core/src/main/java/info/textgrid/middleware/RecordListDelivererDATACITE.java
+++ b/oaipmh-core/src/main/java/info/textgrid/middleware/RecordListDelivererDATACITE.java
@@ -3,12 +3,21 @@ package info.textgrid.middleware;
 import java.io.IOException;
 import java.text.ParseException;
 import java.util.ArrayList;
+import java.util.Hashtable;
 import java.util.List;
+import java.util.Map;
 import javax.xml.datatype.DatatypeConfigurationException;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.elasticsearch.action.search.SearchRequest;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.action.search.SearchScrollRequest;
+import org.elasticsearch.client.RequestOptions;
+import org.elasticsearch.common.unit.TimeValue;
 import org.elasticsearch.index.query.QueryBuilder;
 import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.search.SearchHit;
+import org.elasticsearch.search.builder.SearchSourceBuilder;
 import info.textgrid.middleware.oaipmh.GetRecordType;
 import info.textgrid.middleware.oaipmh.ListRecordsType;
 import info.textgrid.middleware.oaipmh.RecordType;
@@ -16,12 +25,17 @@ import info.textgrid.middleware.oaipmh.RecordType;
 /**
  * @author Maximilian Brodhun, SUB Göttingen
  * @author Stefan E. Funk, SUB Göttingen
- * @version 2021-09-10
+ * @version 2021-10-25
  * @since 2020-06-13
  */
 public class RecordListDelivererDATACITE extends RecordListDelivererAbstract {
 
+  // **
+  // STATICS
+  // **
+
   private static Log log = LogFactory.getLog(RecordListDelivererDATACITE.class);
+  protected static Map<String, Integer> cursorCollector = new Hashtable<String, Integer>();
 
   /**
    * @param textgrid
@@ -159,4 +173,105 @@ public class RecordListDelivererDATACITE extends RecordListDelivererAbstract {
     return result;
   }
 
+  /**
+   * @param query
+   * @param resumptionToken
+   * @param set
+   * @return
+   */
+  private List<String> getFieldsFromESIndex(QueryBuilder query, String resumptionToken,
+      String set) {
+
+    List<String> uriList = new ArrayList<String>();
+
+    QueryBuilder recordFilter;
+    if (this.textgrid) {
+      // We filter out all editions here!
+      recordFilter = QueryBuilders.boolQuery().must(query)
+          .must(QueryBuilders.matchPhraseQuery("format", this.formatToFilter));
+    } else {
+      // Do not filter at all in DH. We need every ID!
+      recordFilter = QueryBuilders.boolQuery().must(query);
+    }
+
+    SearchRequest searchRequest = new SearchRequest(OAI_ESClient.getEsIndex());
+    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
+
+    searchSourceBuilder.query(recordFilter);
+    searchSourceBuilder.size(this.searchResponseSize);
+    searchRequest.source(searchSourceBuilder);
+
+    SearchResponse scrollResp = new SearchResponse();
+
+    if (resumptionToken != null) {
+      SearchScrollRequest scrollRequest = new SearchScrollRequest(resumptionToken);
+      scrollRequest.scroll(TimeValue.timeValueHours(24L));
+
+      try {
+        scrollResp = OAI_ESClient.getEsClient().scroll(scrollRequest, RequestOptions.DEFAULT);
+      } catch (IOException e) {
+        // TODO Auto-generated catch block
+        e.printStackTrace();
+      }
+    } else {
+      searchRequest.source(searchSourceBuilder);
+      searchRequest.scroll(TimeValue.timeValueHours(24L));
+      try {
+        scrollResp = OAI_ESClient.getEsClient().search(searchRequest, RequestOptions.DEFAULT);
+      } catch (IOException e) {
+        // TODO Auto-generated catch block
+        e.printStackTrace();
+      }
+    }
+
+    String scrollID = scrollResp.getScrollId();
+    long completeListSize = scrollResp.getHits().totalHits;
+    setResultSize(completeListSize);
+
+    if (completeListSize > 0) {
+
+      setFoundItems(true);
+      int i = 0;
+
+      for (SearchHit hit : scrollResp.getHits().getHits()) {
+        i++;
+        if (hit != null && hit.getFields() != null) {
+          String id2add;
+          // FIXME Could we not use hit.getId() also for TG hits? Where is the difference?
+          if (this.textgrid) {
+            id2add = hit.getSourceAsMap().get(TGConstants.URI).toString();
+          } else {
+            id2add = hit.getId();
+          }
+          uriList.add(id2add);
+        }
+      }
+      if (resumptionToken != null
+          && this.resTokenForResponse.getCursor().intValue() >= completeListSize) {
+        try {
+          cursorCollector.remove(resumptionToken);
+        } catch (NullPointerException couldNotRemove) {
+          log.info("Could not remove hash value: " + resumptionToken + " from hash map");
+        }
+        this.resTokenForResponse.setValue("");
+      } else {
+        this.resTokenForResponse = OAIPMHUtilities.getResumptionToken(completeListSize,
+            resumptionToken, cursorCollector, scrollID, this.searchResponseSize, i);
+      }
+
+      log.debug("cursorCollector: " + cursorCollector);
+
+    } else {
+      log.info("HALLO");
+      setFoundItems(false);
+    }
+
+    if (this.resTokenForResponse != null) {
+      log.debug("restok value: " + this.resTokenForResponse.getValue());
+      log.debug("restok cursor: " + this.resTokenForResponse.getCursor());
+    }
+
+    return uriList;
+  }
+
 }
diff --git a/oaipmh-core/src/main/java/info/textgrid/middleware/RecordListDelivererDC.java b/oaipmh-core/src/main/java/info/textgrid/middleware/RecordListDelivererDC.java
index ac8c7330..9a808fa5 100644
--- a/oaipmh-core/src/main/java/info/textgrid/middleware/RecordListDelivererDC.java
+++ b/oaipmh-core/src/main/java/info/textgrid/middleware/RecordListDelivererDC.java
@@ -4,6 +4,8 @@ import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.net.URLDecoder;
 import java.text.ParseException;
+import java.util.Hashtable;
+import java.util.Map;
 import javax.xml.datatype.DatatypeConfigurationException;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -44,6 +46,7 @@ public class RecordListDelivererDC extends RecordListDelivererAbstract {
   // **
 
   private static Log log = LogFactory.getLog(RecordListDelivererDC.class);
+  protected static Map<String, Integer> cursorCollector = new Hashtable<String, Integer>();
 
   // **
   // DC-Field Lists
diff --git a/oaipmh-core/src/main/java/info/textgrid/middleware/RecordListDelivererIDIOM.java b/oaipmh-core/src/main/java/info/textgrid/middleware/RecordListDelivererIDIOM.java
index 2625b6df..c854bffa 100644
--- a/oaipmh-core/src/main/java/info/textgrid/middleware/RecordListDelivererIDIOM.java
+++ b/oaipmh-core/src/main/java/info/textgrid/middleware/RecordListDelivererIDIOM.java
@@ -2,6 +2,8 @@ package info.textgrid.middleware;
 
 import java.io.IOException;
 import java.text.ParseException;
+import java.util.Hashtable;
+import java.util.Map;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.elasticsearch.action.search.SearchRequest;
@@ -19,11 +21,19 @@ import info.textgrid.middleware.oaipmh.ListRecordsType;
 import info.textgrid.middleware.oaipmh.ResumptionTokenType;
 
 /**
- *
+ * @author Maximilian Brodhun, SUB Göttingen
+ * @author Stefan E. Funk, SUB Göttingen
+ * @version 2021-10-25
+ * @since
  */
 public class RecordListDelivererIDIOM extends RecordListDelivererAbstract {
 
+  // **
+  // STATICS
+  // **
+
   private static Log log = LogFactory.getLog(RecordListDelivererIDIOM.class);
+  protected static Map<String, Integer> cursorCollector = new Hashtable<String, Integer>();
 
   // Set default to 30, can be changed in oaipmh.properties.
   private int idiomResponseSize = 30;
@@ -136,6 +146,10 @@ public class RecordListDelivererIDIOM extends RecordListDelivererAbstract {
     return recordList;
   }
 
+  // **
+  // GETTERA & SETTERS
+  // **
+
   /**
    * @return
    */
diff --git a/oaipmh-core/src/test/java/info/textgrid/middleware/OaiPmhTextgridOnlineTests.java b/oaipmh-core/src/test/java/info/textgrid/middleware/OaiPmhTextgridOnlineTests.java
index 443807aa..08997e3b 100644
--- a/oaipmh-core/src/test/java/info/textgrid/middleware/OaiPmhTextgridOnlineTests.java
+++ b/oaipmh-core/src/test/java/info/textgrid/middleware/OaiPmhTextgridOnlineTests.java
@@ -30,7 +30,7 @@ import org.junit.Test;
  * 
  * @author Stefan E. Funk, SUB Göttingen
  */
-//@Ignore
+// @Ignore
 public class OaiPmhTextgridOnlineTests {
 
   // TODO Configure config files for all the different OAI-PMH service instances!
@@ -51,6 +51,17 @@ public class OaiPmhTextgridOnlineTests {
   // NOTE Use "mvn tomcat:run" here!
   // private static String host = "http://localhost:8080/oaipmh-webapp/";
 
+  // **
+  // FINALS
+  // **
+
+  private static final String OAIDC_SCHEMA_FORMAT = "oai_dc";
+  private static final String IDIOMMETS_SCHEMA_FORMAT = "oai_idiom_mets";
+  private static final String DATACITE_SCHEMA_FORMAT = "oai_datacite";
+  private static final String EXPECTED_OAIDC_FORMAT_CONTENT = "<oai_dc:dc>";
+  private static final String EXPECTED_IDIOMMETS_FORMAT_CONTENT = "<mets ";
+  private static final String EXPECTED_DATACITE_FORMAT_CONTENT = "<datacite:resource>";
+
   // **
   // STATICS
   // **
@@ -1276,8 +1287,15 @@ public class OaiPmhTextgridOnlineTests {
     System.out.println("\t" + theThreadName + "time: "
         + OaiPmhTestUtilities.getDurationInSecs(timeRunning) + " (loop " + loopCount
         + (maxNumberOfPagesToTest != 0 ? "/" + maxNumberOfPagesToTest : "") + ")");
-    String restok = examineResumptionTokenTag(httpResponse, testOccurance, "",
-        recordsExpectedPerRequest, loopCount, theThreadName);
+
+    String responseString = IOUtils.readStringFromStream((InputStream) httpResponse.getEntity());
+
+    // Test resumption token tags.
+    String restok = examineResumptionTokenTag(responseString, testOccurance,
+        OaiPmhTestUtilities.NO_TOKEN, recordsExpectedPerRequest, loopCount, theThreadName);
+
+    // Test general metadata content, must go conform with the metadata prefix setting.
+    examineContent(responseString, theMetadataPrefix);
 
     while (status == HttpStatus.SC_OK && !restok.equals(OaiPmhTestUtilities.NO_TOKEN)) {
       loopCount += 1;
@@ -1296,8 +1314,14 @@ public class OaiPmhTextgridOnlineTests {
         System.out.println("\t" + theThreadName + "time: "
             + OaiPmhTestUtilities.getDurationInSecs(timeRunning) + " (loop " + loopCount
             + (maxNumberOfPagesToTest != 0 ? "/" + maxNumberOfPagesToTest : "") + ")");
-        restok = examineResumptionTokenTag(httpResponse, testOccurance, restok,
+
+        // Test resumption token tags.
+        responseString = IOUtils.readStringFromStream((InputStream) httpResponse.getEntity());
+        restok = examineResumptionTokenTag(responseString, testOccurance, restok,
             recordsExpectedPerRequest, loopCount, theThreadName);
+
+        // Test general metadata content, must go conform with the metadata prefix setting.
+        examineContent(responseString, theMetadataPrefix);
       }
     }
     // Only check for max loops, if we do have less loops and no resumption token, it will be fine,
@@ -1331,33 +1355,32 @@ public class OaiPmhTextgridOnlineTests {
    *         existing, tag is existing and has no token value.
    * @throws IOException
    */
-  public static String examineResumptionTokenTag(final Response theResponse,
+  public static String examineResumptionTokenTag(final String theResponseString,
       final String recordOrHeader, final String oldtok, final int recordsExpectedPerRequest,
       final int loopCount, final String theThreadName) throws IOException {
 
-    String res = IOUtils.readStringFromStream((InputStream) theResponse.getEntity());
-
     // Test for OAIPMH errors.
-    if (res.contains("<error code=\"badArgument\">")) {
-      String message = theThreadName + OaiPmhTestUtilities.ERROR + " IN OAIPMH RESPONSE: " + res;
+    if (theResponseString.contains("<error code=\"badArgument\">")) {
+      String message =
+          theThreadName + OaiPmhTestUtilities.ERROR + " IN OAIPMH RESPONSE: " + theResponseString;
       System.out.println(message);
       throw new IOException(message);
     }
 
     // Count response objects at first.
     int recordCount = 0;
-    int i = res.indexOf("<" + recordOrHeader + ">", 0);
+    int i = theResponseString.indexOf("<" + recordOrHeader + ">", 0);
     while (i != -1) {
       recordCount++;
       i++;
-      i = res.indexOf("<" + recordOrHeader + ">", i);
+      i = theResponseString.indexOf("<" + recordOrHeader + ">", i);
     }
 
     System.out.println("\t" + theThreadName + recordOrHeader + "s: " + recordCount);
 
     // Check if token tag is existing.
-    int tokStart = res.indexOf("<resumptionToken");
-    int tokEnd = res.indexOf("</resumptionToken");
+    int tokStart = theResponseString.indexOf("<resumptionToken");
+    int tokEnd = theResponseString.indexOf("</resumptionToken");
 
     if (tokStart == -1 && tokEnd == -1) {
       System.out.println("\t" + theThreadName + "token: no token");
@@ -1365,7 +1388,7 @@ public class OaiPmhTextgridOnlineTests {
       return OaiPmhTestUtilities.NO_TOKEN;
     }
 
-    String restokTmp = res.substring(tokStart, tokEnd);
+    String restokTmp = theResponseString.substring(tokStart, tokEnd);
     // Get token tag.
     String toktag = restokTmp.substring(0, restokTmp.indexOf(">") + 1).trim();
     System.out.println("\t" + theThreadName + "tokentag: " + toktag);
@@ -1442,4 +1465,37 @@ public class OaiPmhTextgridOnlineTests {
     return result;
   }
 
+  /**
+   * @param theResponseString
+   * @param theMetadataFormat
+   */
+  private static void examineContent(String theResponseString, String theMetadataFormat) {
+
+    System.out.println(theResponseString);
+
+    // Check for correct metadata content according to metadata prefix.
+    if (theMetadataFormat.equals(OAIDC_SCHEMA_FORMAT)
+        && !theResponseString.contains("metadataPrefix=\"" + OAIDC_SCHEMA_FORMAT + "\"")
+        && !theResponseString.contains(EXPECTED_OAIDC_FORMAT_CONTENT)) {
+      System.out
+          .println(OAIDC_SCHEMA_FORMAT + " needs to deliver content with schema: "
+              + EXPECTED_OAIDC_FORMAT_CONTENT + "!");
+      assertTrue(false);
+    } else if (theMetadataFormat.equals(IDIOMMETS_SCHEMA_FORMAT)
+        && !theResponseString.contains("metadataPrefix=\"" + IDIOMMETS_SCHEMA_FORMAT + "\"")
+        && !theResponseString.contains(EXPECTED_IDIOMMETS_FORMAT_CONTENT)) {
+      System.out
+          .println(IDIOMMETS_SCHEMA_FORMAT + " needs to deliver content with schema: "
+              + EXPECTED_IDIOMMETS_FORMAT_CONTENT + "!");
+      assertTrue(false);
+    } else if (theMetadataFormat.equals(DATACITE_SCHEMA_FORMAT)
+        && !theResponseString.contains("metadataPrefix=\"" + DATACITE_SCHEMA_FORMAT + "\"")
+        && !theResponseString.contains(EXPECTED_DATACITE_FORMAT_CONTENT)) {
+      System.out
+          .println(DATACITE_SCHEMA_FORMAT + " needs to deliver content with schema: "
+              + EXPECTED_DATACITE_FORMAT_CONTENT + "!");
+      assertTrue(false);
+    }
+  }
+
 }
diff --git a/oaipmh-webapp/pom.xml b/oaipmh-webapp/pom.xml
index ba387c57..57f2511f 100644
--- a/oaipmh-webapp/pom.xml
+++ b/oaipmh-webapp/pom.xml
@@ -5,7 +5,7 @@
 	<parent>
 		<artifactId>oaipmh</artifactId>
 		<groupId>info.textgrid.middleware</groupId>
-        <version>4.0.5-SNAPSHOT</version>
+        <version>4.0.6-SNAPSHOT</version>
 	</parent>
 	<groupId>info.textgrid.middleware</groupId>
 	<artifactId>oaipmh-webapp</artifactId>
diff --git a/pom.xml b/pom.xml
index 63729178..95f65ba0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
 	<modelVersion>4.0.0</modelVersion>
 	<groupId>info.textgrid.middleware</groupId>
 	<artifactId>oaipmh</artifactId>
-	<version>4.0.5-SNAPSHOT</version>
+	<version>4.0.6-SNAPSHOT</version>
 	<packaging>pom</packaging>
 	<name>DARIAHDE :: OAI-PMH DataProvider</name>
 	<properties>
-- 
GitLab