/** * Licensed to The Apereo Foundation under one or more contributor license * agreements. See the NOTICE file distributed with this work for additional * information regarding copyright ownership. * * * The Apereo Foundation licenses this file to you under the Educational * Community License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License * at: * * http://opensource.org/licenses/ecl2.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * */ package org.opencastproject.oaipmh.harvester; import static org.apache.commons.lang3.StringUtils.trimToNull; import static org.opencastproject.util.data.Option.option; import org.opencastproject.oaipmh.OaiPmhConstants; import org.opencastproject.util.data.Option; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import java.util.Iterator; import java.util.NoSuchElementException; /** * The "ListRecords" response. * See <a href="http://www.openarchives.org/OAI/openarchivesprotocol.html#ListRecords">4.5 ListRecords</a> for further * information. * <p> * todo implement missing element accessors */ public class ListRecordsResponse extends OaiPmhResponse { public ListRecordsResponse(Document doc) { super(doc); } public boolean isErrorBadArgument() { return isError(OaiPmhConstants.ERROR_BAD_ARGUMENT); } public boolean isErrorBadResumptionToken() { return isError(OaiPmhConstants.ERROR_BAD_RESUMPTION_TOKEN); } public boolean isErrorCannotDisseminateFormat() { return isError(OaiPmhConstants.ERROR_CANNOT_DISSEMINATE_FORMAT); } public boolean isErrorNoRecordsMatch() { return isError(OaiPmhConstants.ERROR_NO_RECORDS_MATCH); } public boolean isErrorNoSetHierarchy() { return isError(OaiPmhConstants.ERROR_NO_SET_HIERARCHY); } /** * Get the content of all metadata elements in the current response. */ public NodeList getMetadataElems() { return xpathNodeList("/oai20:OAI-PMH/oai20:ListRecords/oai20:record/oai20:metadata/*[1]"); } /** * Get all records in the current response. * <pre> * <record> * <header>... * </header> * <metadata>... * </metadata> * </record> * </pre> */ public NodeList getRecords() { return xpathNodeList("/oai20:OAI-PMH/oai20:ListRecords/oai20:record"); } /** * Extract the content, i.e. the first child node, of the metadata node of a record. * <pre> * <record> * <header>... * </header> * <metadata> * <myMd> * </myMd> * </metadata> * </record> * * => * * <myMd> * </myMd> * </pre> */ public static Node metadataOfRecord(Node recordNode) { return xpathNode(createXPath(), recordNode, "oai20:metadata/*[1]"); } /** * Get all records performing a complete request resuming any partial responses. */ public static Iterable<Node> getAllRecords(final ListRecordsResponse first, final OaiPmhRepositoryClient client) { return new Iterable<Node>() { @Override public Iterator<Node> iterator() { return new ResponseIterator(first) { @Override protected OaiPmhRepositoryClient getClient() { return client; } @Override protected NodeList extractNodes(ListRecordsResponse response) { return response.getRecords(); } }; } }; } /** * Get all metadata performing a complete request resuming any partial responses. */ public static Iterable<Node> getAllMetadataElems(final ListRecordsResponse first, final OaiPmhRepositoryClient client) { return new Iterable<Node>() { @Override public Iterator<Node> iterator() { return new ResponseIterator(first) { @Override protected OaiPmhRepositoryClient getClient() { return client; } @Override protected NodeList extractNodes(ListRecordsResponse response) { return response.getMetadataElems(); } }; } }; } public String getMetadataPrefix() { return xpathString("/oai20:OAI-PMH/oai20:request/@metadataPrefix"); } public Option<String> getResumptionToken() { return option(trimToNull(xpathString("/oai20:OAI-PMH/oai20:ListRecords/oai20:resumptionToken/text()"))); } // private abstract static class ResponseIterator implements Iterator<Node> { private NodeList elems; private Option<String> token; private int i; ResponseIterator(ListRecordsResponse response) { initIteration(response); } private void initIteration(ListRecordsResponse response) { elems = extractNodes(response); token = response.getResumptionToken(); i = 0; } protected abstract OaiPmhRepositoryClient getClient(); /** * Extract the relevant part of the response. */ protected abstract NodeList extractNodes(ListRecordsResponse response); @Override public boolean hasNext() { if (hasNextInCurrent()) { return true; } else { if (token.isSome()) { initIteration(getClient().resumeListRecords(token.get())); return hasNextInCurrent(); } else { return false; } } } @Override public Node next() { if (!hasNext()) throw new NoSuchElementException(); return elems.item(i++); } @Override public void remove() { throw new UnsupportedOperationException(); } private boolean hasNextInCurrent() { return i < elems.getLength(); } } }