dnet-docker/dnet-app/libs/dnet-oai-common/src/main/java/eu/dnetlib/common/oai/OaiClient.java

189 lines
6.5 KiB
Java

package eu.dnetlib.common.oai;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import eu.dnetlib.domain.oai.OaiIdentifier;
import eu.dnetlib.domain.oai.OaiInfo;
import eu.dnetlib.domain.oai.OaiMetadataFormat;
import eu.dnetlib.domain.oai.OaiRecord;
import eu.dnetlib.domain.oai.OaiSet;
public class OaiClient {
public OaiResponse<List<OaiSet>> listSets(final String baseUrl, final String resumptionToken) throws Exception {
final OaiRequest req = StringUtils.isNotBlank(resumptionToken)
? OaiRequest.newListSetsWithToken(baseUrl, resumptionToken)
: OaiRequest.newListSets(baseUrl);
final OaiResponse<List<OaiSet>> res = new OaiResponse<>();
callOaiVerb(req, res, doc -> doc
.selectNodes("//*[local-name()='ListSets']/*[local-name()='set']")
.stream()
.map(node -> (Element) node)
.map(OaiSetImpl::new)
.map(set -> (OaiSet) set)
.toList());
return res;
}
public OaiResponse<List<OaiMetadataFormat>> listMetadataFormats(final String baseUrl) throws Exception {
final OaiRequest req = OaiRequest.newListMetadataFormats(baseUrl);
final OaiResponse<List<OaiMetadataFormat>> res = new OaiResponse<>();
callOaiVerb(req, res, doc -> doc
.selectNodes("//*[local-name()='ListMetadataFormats']/*[local-name()='metadataFormat']")
.stream()
.map(node -> (Element) node)
.map(OaiMetadataFormatImpl::new)
.map(set -> (OaiMetadataFormat) set)
.toList());
return res;
}
public OaiResponse<List<OaiRecord<String, String>>> listRecords(final String baseUrl, final String mdPrefix, final String set, final String resumptionToken)
throws Exception {
final OaiRequest req = StringUtils.isNotBlank(resumptionToken)
? OaiRequest.newListRecordsWithToken(baseUrl, resumptionToken)
: OaiRequest.newListRecords(baseUrl, mdPrefix, set);
final OaiResponse<List<OaiRecord<String, String>>> res = new OaiResponse<>();
callOaiVerb(req, res, doc -> doc
.selectNodes("//*[local-name()='ListRecords']/*[local-name()='record']")
.stream()
.map(node -> (Element) node)
.map(OaiRecordImpl::new)
.map(r -> (OaiRecord<String, String>) r)
.toList());
return res;
}
public OaiResponse<List<OaiIdentifier<String>>> listIdentifiers(final String baseUrl, final String mdPrefix, final String set, final String resumptionToken)
throws Exception {
final OaiRequest req = StringUtils.isNotBlank(resumptionToken)
? OaiRequest.newListIdentifiersWithToken(baseUrl, resumptionToken)
: OaiRequest.newListIdentifiers(baseUrl, mdPrefix, set);
final OaiResponse<List<OaiIdentifier<String>>> res = new OaiResponse<>();
callOaiVerb(req, res, doc -> doc
.selectNodes("//*[local-name()='ListIdentifiers']/*[local-name()='header']")
.stream()
.map(node -> (Element) node)
.map(OaiIdentifierImpl::new)
.map(r -> (OaiIdentifier<String>) r)
.toList());
return res;
}
public OaiResponse<OaiRecord<String, String>> getRecord(final String baseUrl, final String mdPrefix, final String id) throws Exception {
final OaiRequest req = OaiRequest.newGetRecord(baseUrl, mdPrefix, id);
final OaiResponse<OaiRecord<String, String>> res = new OaiResponse<>();
callOaiVerb(req, res, doc -> doc
.selectNodes("//*[local-name()='GetRecord']/*[local-name()='record']")
.stream()
.map(node -> (Element) node)
.map(OaiRecordImpl::new)
.map(r -> (OaiRecord<String, String>) r)
.findFirst()
.orElseThrow());
return res;
}
public OaiResponse<OaiInfo<String>> info(final String baseUrl) throws Exception {
final OaiRequest req = OaiRequest.newIdentify(baseUrl);
final OaiResponse<OaiInfo<String>> res = new OaiResponse<>();
callOaiVerb(req, res, doc -> doc
.selectNodes("//*[local-name()='Identify']")
.stream()
.map(node -> (Element) node)
.map(OaiInfoImpl::new)
.map(r -> (OaiInfo<String>) r)
.findFirst()
.orElseThrow());
return res;
}
private <T> void callOaiVerb(final OaiRequest req, final OaiResponse<T> res, final Function<Document, T> processBody) {
res.setVerb(req.getVerb());
final long start = System.currentTimeMillis();
try {
final HttpHeaders headers = new HttpHeaders();
headers.set(HttpHeaders.ACCEPT, MediaType.APPLICATION_XML_VALUE);
final Map<String, Object> params = req.toQueryParams();
final UriComponentsBuilder urlBuilder = UriComponentsBuilder.fromHttpUrl(req.getBaseUrl());
params.keySet().forEach(k -> urlBuilder.queryParam(k, "{" + k + "}"));
final ResponseEntity<String> httpResponse =
new RestTemplate().exchange(urlBuilder.encode().toUriString(), HttpMethod.GET, new HttpEntity<>(headers), String.class, params);
res.setHttpCode(httpResponse.getStatusCode().value());
if (httpResponse.getStatusCode().isError()) {
res.setValid(false);
res.setError("ERROR: " + httpResponse.getStatusCode().value());
} else {
final Document doc = DocumentHelper.parseText(httpResponse.getBody());
final Node node = doc.selectSingleNode("//*[local-name() = 'resumptionToken']");
if (node != null) {
res.setSize(doc.selectNodes("//*[local-name()='" + req.getVerb() + "']/*[local-name() != 'resumptionToken']").size());
res.setCursor(NumberUtils.toInt(node.valueOf("@cursor"), -1));
res.setTotal(NumberUtils.toInt(node.valueOf("@completeListSize"), -1));
if (OaiRequest.LISTSETS.equals(req.getVerb())) {
res.setNextCall(OaiRequest.newListSetsWithToken(req.getBaseUrl(), node.getText()));
} else if (OaiRequest.LISTIDENTIFIERS.equals(req.getVerb())) {
res.setNextCall(OaiRequest.newListIdentifiersWithToken(req.getBaseUrl(), node.getText()));
} else if (OaiRequest.LISTRECORDS.equals(req.getVerb())) {
res.setNextCall(OaiRequest.newListRecordsWithToken(req.getBaseUrl(), node.getText()));
}
}
res.setBody(processBody.apply(doc));
res.setValid(true);
}
} catch (final Throwable e) {
res.setValid(false);
res.setError(e.getMessage());
} finally {
res.setTime(System.currentTimeMillis() - start);
}
}
}