diff --git a/dspace-api/src/main/java/org/dspace/importer/external/datacite/DataCiteImportMetadataSourceServiceImpl.java b/dspace-api/src/main/java/org/dspace/importer/external/datacite/DataCiteImportMetadataSourceServiceImpl.java index b4235f1fe838..59214ac1176e 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/datacite/DataCiteImportMetadataSourceServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/datacite/DataCiteImportMetadataSourceServiceImpl.java @@ -9,29 +9,28 @@ import java.util.ArrayList; import java.util.Collection; -import java.util.LinkedHashMap; +import java.util.HashMap; +import java.util.Iterator; import java.util.List; -import java.util.concurrent.Callable; +import java.util.Map; import javax.el.MethodNotFoundException; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; -import javax.ws.rs.client.Invocation; import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.Response; -import com.google.gson.Gson; -import com.jayway.jsonpath.JsonPath; -import com.jayway.jsonpath.ReadContext; -import net.minidev.json.JSONArray; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.lang3.StringUtils; -import org.apache.http.client.methods.HttpGet; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.dspace.content.Item; import org.dspace.importer.external.datamodel.ImportRecord; import org.dspace.importer.external.datamodel.Query; import org.dspace.importer.external.exception.MetadataSourceException; +import org.dspace.importer.external.liveimportclient.service.LiveImportClient; import org.dspace.importer.external.service.AbstractImportMetadataSourceService; import org.dspace.importer.external.service.DoiCheck; import org.dspace.importer.external.service.components.QuerySource; +import org.springframework.beans.factory.annotation.Autowired; /** * Implements a data source for querying Datacite @@ -39,13 +38,21 @@ * * optional Affiliation informations are not part of the API request. * https://support.datacite.org/docs/can-i-see-more-detailed-affiliation-information-in-the-rest-api - * + * * @author Pasquale Cavallo (pasquale.cavallo at 4science dot it) * @author Florian Gantner (florian.gantner@uni-bamberg.de) * */ public class DataCiteImportMetadataSourceServiceImpl - extends AbstractImportMetadataSourceService implements QuerySource { + extends AbstractImportMetadataSourceService implements QuerySource { + private final static Logger log = LogManager.getLogger(); + + @Autowired + private LiveImportClient liveImportClient; + + private final int timeoutMs = 180000; + + private final String url = "https://api.datacite.org/dois/"; private WebTarget webTarget; @@ -56,91 +63,97 @@ public String getImportSource() { @Override public void init() throws Exception { - Client client = ClientBuilder.newClient(); - webTarget = client.target("https://api.datacite.org/dois/"); } @Override public ImportRecord getRecord(String recordId) throws MetadataSourceException { - List records = null; - String id = getID(recordId); - if (StringUtils.isNotBlank(id)) { - records = retry(new SearchByIdCallable(id)); - } else { - records = retry(new SearchByIdCallable(recordId)); + Collection records = getRecords(recordId, 0, 1); + if (records.size() == 0) { + return null; } - return records == null || records.isEmpty() ? null : records.get(0); + return records.stream().findFirst().get(); } @Override public int getRecordsCount(String query) throws MetadataSourceException { - String id = getID(query); - if (StringUtils.isNotBlank(id)) { - return retry(new DoiCheckCallable(id)); - } - return retry(new CountByQueryCallable(query)); + Collection records = getRecords(query, 0, -1); + return records == null ? 0 : records.size(); } @Override public int getRecordsCount(Query query) throws MetadataSourceException { String id = getID(query.toString()); - if (StringUtils.isNotBlank(id)) { - return retry(new DoiCheckCallable(id)); - } - return retry(new CountByQueryCallable(query)); + return getRecordsCount(StringUtils.isBlank(id) ? query.toString() : id); } @Override public Collection getRecords(String query, int start, int count) throws MetadataSourceException { - String id = getID(query.toString()); - if (StringUtils.isNotBlank(id)) { - return retry(new SearchByIdCallable(id)); + List records = new ArrayList<>(); + String id = getID(query); + Map> params = new HashMap<>(); + Map uriParameters = new HashMap<>(); + params.put("uriParameters", uriParameters); + if (StringUtils.isBlank(id)) { + id = query; + } + uriParameters.put("query", id); + String responseString = liveImportClient.executeHttpGetRequest(timeoutMs, url, params); + JsonNode jsonNode = convertStringJsonToJsonNode(responseString); + JsonNode dataNode = jsonNode.at("/data"); + if (dataNode.isArray()) { + Iterator iterator = dataNode.iterator(); + while (iterator.hasNext()) { + JsonNode singleDoiNode = iterator.next(); + String json = singleDoiNode.at("/attributes").toString(); + records.add(transformSourceRecords(json)); + } + } else { + String json = dataNode.at("/attributes").toString(); + records.add(transformSourceRecords(json)); } - return retry(new SearchByQueryCallable(query, count, start)); + + return records; + } + + private JsonNode convertStringJsonToJsonNode(String json) { + try { + return new ObjectMapper().readTree(json); + } catch (JsonProcessingException e) { + log.error("Unable to process json response.", e); + } + return null; } @Override public Collection getRecords(Query query) throws MetadataSourceException { String id = getID(query.toString()); - if (StringUtils.isNotBlank(id)) { - return retry(new SearchByIdCallable(id)); - } - return retry(new SearchByQueryCallable(query)); + return getRecords(StringUtils.isBlank(id) ? query.toString() : id, 0, -1); } @Override public ImportRecord getRecord(Query query) throws MetadataSourceException { - List records = null; String id = getID(query.toString()); - if (StringUtils.isNotBlank(id)) { - records = retry(new SearchByIdCallable(id)); - } else { - records = retry(new SearchByIdCallable(query)); - } - return records == null || records.isEmpty() ? null : records.get(0); + return getRecord(StringUtils.isBlank(id) ? query.toString() : id); } @Override public Collection findMatchingRecords(Query query) throws MetadataSourceException { String id = getID(query.toString()); - if (StringUtils.isNotBlank(id)) { - return retry(new SearchByIdCallable(id)); - } - return retry(new FindMatchingRecordCallable(query)); + return getRecords(StringUtils.isBlank(id) ? query.toString() : id, 0, -1); } @Override public Collection findMatchingRecords(Item item) throws MetadataSourceException { - throw new MethodNotFoundException("This method is not implemented for Datacite"); + throw new MethodNotFoundException("This method is not implemented for DataCite"); } public String getID(String query) { if (DoiCheck.isDoi(query)) { return query; } - //Workaround for encoded slashes. + // Workaround for encoded slashes. if (query.contains("%252F")) { query = query.replace("%252F", "/"); } @@ -149,231 +162,4 @@ public String getID(String query) { } return StringUtils.EMPTY; } - - private class SearchByQueryCallable implements Callable> { - - private Query query; - - private SearchByQueryCallable(String queryString, Integer maxResult, Integer start) { - query = new Query(); - query.addParameter("query", queryString); - query.addParameter("count", maxResult); - query.addParameter("start", start); - } - - private SearchByQueryCallable(Query query) { - this.query = query; - } - - @Override - public List call() throws Exception { - List results = new ArrayList<>(); - HttpGet method = null; - try { - Integer count = query.getParameterAsClass("count", Integer.class); - Integer start = query.getParameterAsClass("start", Integer.class); - WebTarget local = webTarget.queryParam("query", query.getParameterAsClass("query", String.class)); - if (count != null) { - local = local.queryParam("rows", count); - } - if (start != null) { - local = local.queryParam("offset", start); - } - Invocation.Builder invocationBuilder = local.request(); - Response response = invocationBuilder.get(); - if (response.getStatus() != 200) { - return null; - } - String responseString = response.readEntity(String.class); - ReadContext ctx = JsonPath.parse(responseString); - Object o = ctx.read("$.data.attributes"); - if (o.getClass().isAssignableFrom(JSONArray.class)) { - JSONArray array = (JSONArray)o; - int size = array.size(); - for (int index = 0; index < size; index++) { - Gson gson = new Gson(); - String innerJson = gson.toJson(array.get(index), LinkedHashMap.class); - results.add(transformSourceRecords(innerJson)); - } - } else { - results.add(transformSourceRecords(o.toString())); - } - return results; - } catch (Exception e) { - throw new RuntimeException(e.getMessage(), e); - } finally { - if (method != null) { - method.releaseConnection(); - } - } - } - - } - - private class SearchByIdCallable implements Callable> { - private Query query; - - private SearchByIdCallable(Query query) { - this.query = query; - } - - private SearchByIdCallable(String id) { - this.query = new Query(); - query.addParameter("id", id); - } - - @Override - public List call() throws Exception { - List results = new ArrayList<>(); - HttpGet method = null; - try { - WebTarget local = webTarget.path(query.getParameterAsClass("id", String.class)); - Invocation.Builder invocationBuilder = local.request(); - Response response = invocationBuilder.get(); - if (response.getStatus() != 200) { - return null; - } - String responseString = response.readEntity(String.class); - ReadContext ctx = JsonPath.parse(responseString); - Object o = ctx.read("$.data.attributes"); - if (o.getClass().isAssignableFrom(JSONArray.class)) { - JSONArray array = (JSONArray)o; - int size = array.size(); - for (int index = 0; index < size; index++) { - Gson gson = new Gson(); - String innerJson = gson.toJson(array.get(index), LinkedHashMap.class); - results.add(transformSourceRecords(innerJson)); - } - } else { - Gson gson = new Gson(); - results.add(transformSourceRecords(gson.toJson(o, Object.class))); - } - return results; - } catch (Exception e) { - throw new RuntimeException(e.getMessage(), e); - } finally { - if (method != null) { - method.releaseConnection(); - } - } - } - } - - private class FindMatchingRecordCallable implements Callable> { - - private Query query; - - private FindMatchingRecordCallable(Query q) { - query = q; - } - - @Override - public List call() throws Exception { - String queryValue = query.getParameterAsClass("query", String.class); - Integer count = query.getParameterAsClass("count", Integer.class); - Integer start = query.getParameterAsClass("start", Integer.class); - List results = new ArrayList<>(); - HttpGet method = null; - try { - WebTarget local = webTarget; - if (queryValue != null) { - local = local.queryParam("query", queryValue); - } - if (count != null) { - local = local.queryParam("page[size]", count); - } - if (start != null) { - local = local.queryParam("page[number]", start); - } - Invocation.Builder invocationBuilder = local.request(); - Response response = invocationBuilder.get(); - if (response.getStatus() != 200) { - return null; - } - String responseString = response.readEntity(String.class); - ReadContext ctx = JsonPath.parse(responseString); - Object o = ctx.read("$.data.attributes"); - if (o.getClass().isAssignableFrom(JSONArray.class)) { - JSONArray array = (JSONArray)o; - int size = array.size(); - for (int index = 0; index < size; index++) { - Gson gson = new Gson(); - String innerJson = gson.toJson(array.get(index), LinkedHashMap.class); - results.add(transformSourceRecords(innerJson)); - } - } else { - results.add(transformSourceRecords(o.toString())); - } - return results; - } catch (Exception e) { - throw new RuntimeException(e.getMessage(), e); - } finally { - if (method != null) { - method.releaseConnection(); - } - } - } - - } - - private class CountByQueryCallable implements Callable { - private Query query; - - - private CountByQueryCallable(String queryString) { - query = new Query(); - query.addParameter("query", queryString); - } - - private CountByQueryCallable(Query query) { - this.query = query; - } - - - @Override - public Integer call() throws Exception { - HttpGet method = null; - try { - WebTarget local = webTarget.queryParam("query", query.getParameterAsClass("query", String.class)); - Invocation.Builder invocationBuilder = local.request(); - Response response = invocationBuilder.get(); - if (response.getStatus() != 200) { - return null; - } - String responseString = response.readEntity(String.class); - ReadContext ctx = JsonPath.parse(responseString); - return ctx.read("$.meta.total"); - } catch (Exception e) { - throw new RuntimeException(e.getMessage(), e); - } finally { - if (method != null) { - method.releaseConnection(); - } - } - } - } - - private class DoiCheckCallable implements Callable { - - private final Query query; - - private DoiCheckCallable(final String id) { - final Query query = new Query(); - query.addParameter("id", id); - this.query = query; - } - - private DoiCheckCallable(final Query query) { - this.query = query; - } - - @Override - public Integer call() throws Exception { - WebTarget local = webTarget.path(query.getParameterAsClass("id", String.class)); - Invocation.Builder invocationBuilder = local.request(); - Response response = invocationBuilder.head(); - return response.getStatus() == 200 ? 1 : 0; - } - } - } diff --git a/dspace-api/src/test/data/dspaceFolder/config/spring/api/external-services.xml b/dspace-api/src/test/data/dspaceFolder/config/spring/api/external-services.xml index dabbde22ec93..37e1fb508953 100644 --- a/dspace-api/src/test/data/dspaceFolder/config/spring/api/external-services.xml +++ b/dspace-api/src/test/data/dspaceFolder/config/spring/api/external-services.xml @@ -103,3 +103,4 @@ + diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/DataCiteImportMetadataSourceServiceIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/DataCiteImportMetadataSourceServiceIT.java new file mode 100644 index 000000000000..466b14a863b9 --- /dev/null +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/DataCiteImportMetadataSourceServiceIT.java @@ -0,0 +1,130 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.when; + +import java.io.InputStream; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import javax.el.MethodNotFoundException; + +import org.apache.commons.io.IOUtils; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.impl.client.CloseableHttpClient; +import org.dspace.builder.CollectionBuilder; +import org.dspace.builder.CommunityBuilder; +import org.dspace.builder.ItemBuilder; +import org.dspace.content.Item; +import org.dspace.importer.external.datacite.DataCiteImportMetadataSourceServiceImpl; +import org.dspace.importer.external.datamodel.ImportRecord; +import org.dspace.importer.external.liveimportclient.service.LiveImportClientImpl; +import org.dspace.importer.external.metadatamapping.MetadatumDTO; +import org.junit.Test; +import org.mockito.ArgumentMatchers; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; + + +/** + * Integration tests for {@link DataCiteImportMetadataSourceServiceImpl} + * + * @author Mykhaylo Boychuk (mykhaylo.boychuk at 4science.com) + */ +public class DataCiteImportMetadataSourceServiceIT extends AbstractLiveImportIntegrationTest { + + @Autowired + private LiveImportClientImpl liveImportClientImpl; + + @Autowired + private DataCiteImportMetadataSourceServiceImpl dataCiteServiceImpl; + + @Test + public void dataCiteImportMetadataGetRecordsTest() throws Exception { + context.turnOffAuthorisationSystem(); + CloseableHttpClient originalHttpClient = liveImportClientImpl.getHttpClient(); + CloseableHttpClient httpClient = Mockito.mock(CloseableHttpClient.class); + try (InputStream dataCiteResp = getClass().getResourceAsStream("dataCite-test.json")) { + String dataCiteRespXmlResp = IOUtils.toString(dataCiteResp, Charset.defaultCharset()); + + liveImportClientImpl.setHttpClient(httpClient); + CloseableHttpResponse response = mockResponse(dataCiteRespXmlResp, 200, "OK"); + when(httpClient.execute(ArgumentMatchers.any())).thenReturn(response); + + context.restoreAuthSystemState(); + ArrayList collection2match = getRecords(); + Collection recordsImported = dataCiteServiceImpl.getRecords("10.48550/arxiv.2207.04779", + 0, -1); + assertEquals(1, recordsImported.size()); + matchRecords(new ArrayList<>(recordsImported), collection2match); + } finally { + liveImportClientImpl.setHttpClient(originalHttpClient); + } + } + + @Test + public void dataCiteImportMetadataGetRecordsCountTest() throws Exception { + context.turnOffAuthorisationSystem(); + CloseableHttpClient originalHttpClient = liveImportClientImpl.getHttpClient(); + CloseableHttpClient httpClient = Mockito.mock(CloseableHttpClient.class); + try (InputStream dataciteResp = getClass().getResourceAsStream("dataCite-test.json")) { + String dataciteTextResp = IOUtils.toString(dataciteResp, Charset.defaultCharset()); + + liveImportClientImpl.setHttpClient(httpClient); + CloseableHttpResponse response = mockResponse(dataciteTextResp, 200, "OK"); + when(httpClient.execute(ArgumentMatchers.any())).thenReturn(response); + + context.restoreAuthSystemState(); + int tot = dataCiteServiceImpl.getRecordsCount("10.48550/arxiv.2207.04779"); + assertEquals(1, tot); + } finally { + liveImportClientImpl.setHttpClient(originalHttpClient); + } + } + + @Test(expected = MethodNotFoundException.class) + public void dataCiteImportMetadataFindMatchingRecordsTest() throws Exception { + context.turnOffAuthorisationSystem(); + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + + org.dspace.content.Collection col1 = CollectionBuilder.createCollection(context, parentCommunity) + .withName("Collection 1") + .build(); + + Item testItem = ItemBuilder.createItem(context, col1) + .withTitle("test item") + .withIssueDate("2021") + .build(); + + context.restoreAuthSystemState(); + dataCiteServiceImpl.findMatchingRecords(testItem); + } + + private ArrayList getRecords() { + ArrayList records = new ArrayList<>(); + //define first record + List metadatums = new ArrayList<>(); + MetadatumDTO title = createMetadatumDTO("dc", "title", null, + "Mathematical Proof Between Generations"); + MetadatumDTO doi = createMetadatumDTO("dc", "identifier", "doi", "10.48550/arxiv.2207.04779"); + + metadatums.add(title); + metadatums.add(doi); + + ImportRecord firstRecord = new ImportRecord(metadatums); + + records.add(firstRecord); + return records; + } + +} diff --git a/dspace-server-webapp/src/test/resources/org/dspace/app/rest/dataCite-test.json b/dspace-server-webapp/src/test/resources/org/dspace/app/rest/dataCite-test.json new file mode 100644 index 000000000000..8ede6f29a08e --- /dev/null +++ b/dspace-server-webapp/src/test/resources/org/dspace/app/rest/dataCite-test.json @@ -0,0 +1 @@ +{"data":{"id":"10.48550/arxiv.2207.04779","type":"dois","attributes":{"doi":"10.48550/arxiv.2207.04779","prefix":"10.48550","suffix":"arxiv.2207.04779","identifiers":[{"identifier":"2207.04779","identifierType":"arXiv"}],"alternateIdentifiers":[{"alternateIdentifierType":"arXiv","alternateIdentifier":"2207.04779"}],"creators":[{"name":"Bayer, Jonas","nameType":"Personal","givenName":"Jonas","familyName":"Bayer","affiliation":[],"nameIdentifiers":[]},{"name":"Benzmüller, Christoph","nameType":"Personal","givenName":"Christoph","familyName":"Benzmüller","affiliation":[],"nameIdentifiers":[]},{"name":"Buzzard, Kevin","nameType":"Personal","givenName":"Kevin","familyName":"Buzzard","affiliation":[],"nameIdentifiers":[]},{"name":"David, Marco","nameType":"Personal","givenName":"Marco","familyName":"David","affiliation":[],"nameIdentifiers":[]},{"name":"Lamport, Leslie","nameType":"Personal","givenName":"Leslie","familyName":"Lamport","affiliation":[],"nameIdentifiers":[]},{"name":"Matiyasevich, Yuri","nameType":"Personal","givenName":"Yuri","familyName":"Matiyasevich","affiliation":[],"nameIdentifiers":[]},{"name":"Paulson, Lawrence","nameType":"Personal","givenName":"Lawrence","familyName":"Paulson","affiliation":[],"nameIdentifiers":[]},{"name":"Schleicher, Dierk","nameType":"Personal","givenName":"Dierk","familyName":"Schleicher","affiliation":[],"nameIdentifiers":[]},{"name":"Stock, Benedikt","nameType":"Personal","givenName":"Benedikt","familyName":"Stock","affiliation":[],"nameIdentifiers":[]},{"name":"Zelmanov, Efim","nameType":"Personal","givenName":"Efim","familyName":"Zelmanov","affiliation":[],"nameIdentifiers":[]}],"titles":[{"title":"Mathematical Proof Between Generations"}],"publisher":"arXiv","container":{},"publicationYear":2022,"subjects":[{"lang":"en","subject":"History and Overview (math.HO)","subjectScheme":"arXiv"},{"lang":"en","subject":"Logic in Computer Science (cs.LO)","subjectScheme":"arXiv"},{"subject":"FOS: Mathematics","subjectScheme":"Fields of Science and Technology (FOS)"},{"subject":"FOS: Mathematics","schemeUri":"http://www.oecd.org/science/inno/38235147.pdf","subjectScheme":"Fields of Science and Technology (FOS)"},{"subject":"FOS: Computer and information sciences","subjectScheme":"Fields of Science and Technology (FOS)"},{"subject":"FOS: Computer and information sciences","schemeUri":"http://www.oecd.org/science/inno/38235147.pdf","subjectScheme":"Fields of Science and Technology (FOS)"}],"contributors":[],"dates":[{"date":"2022-07-08T14:42:33Z","dateType":"Submitted","dateInformation":"v1"},{"date":"2022-07-13T00:14:24Z","dateType":"Updated","dateInformation":"v1"},{"date":"2022-07","dateType":"Available","dateInformation":"v1"},{"date":"2022","dateType":"Issued"}],"language":null,"types":{"ris":"GEN","bibtex":"misc","citeproc":"article","schemaOrg":"CreativeWork","resourceType":"Article","resourceTypeGeneral":"Preprint"},"relatedIdentifiers":[],"relatedItems":[],"sizes":[],"formats":[],"version":"1","rightsList":[{"rights":"arXiv.org perpetual, non-exclusive license","rightsUri":"http://arxiv.org/licenses/nonexclusive-distrib/1.0/"}],"descriptions":[{"description":"A proof is one of the most important concepts of mathematics. However, there is a striking difference between how a proof is defined in theory and how it is used in practice. This puts the unique status of mathematics as exact science into peril. Now may be the time to reconcile theory and practice, i.e. precision and intuition, through the advent of computer proof assistants. For the most time this has been a topic for experts in specialized communities. However, mathematical proofs have become increasingly sophisticated, stretching the boundaries of what is humanly comprehensible, so that leading mathematicians have asked for formal verification of their proofs. At the same time, major theorems in mathematics have recently been computer-verified by people from outside of these communities, even by beginning students. This article investigates the gap between the different definitions of a proof and possibilities to build bridges. It is written as a polemic or a collage by different members of the communities in mathematics and computer science at different stages of their careers, challenging well-known preconceptions and exploring new perspectives.","descriptionType":"Abstract"},{"description":"17 pages, 1 figure","descriptionType":"Other"}],"geoLocations":[],"fundingReferences":[],"xml":"PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHJlc291cmNlIHhtbG5zPSJodHRwOi8vZGF0YWNpdGUub3JnL3NjaGVtYS9rZXJuZWwtNCIgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeHNpOnNjaGVtYUxvY2F0aW9uPSJodHRwOi8vZGF0YWNpdGUub3JnL3NjaGVtYS9rZXJuZWwtNCBodHRwOi8vc2NoZW1hLmRhdGFjaXRlLm9yZy9tZXRhL2tlcm5lbC00LjMvbWV0YWRhdGEueHNkIj4KICA8aWRlbnRpZmllciBpZGVudGlmaWVyVHlwZT0iRE9JIj4xMC40ODU1MC9BUlhJVi4yMjA3LjA0Nzc5PC9pZGVudGlmaWVyPgogIDxhbHRlcm5hdGVJZGVudGlmaWVycz4KICAgIDxhbHRlcm5hdGVJZGVudGlmaWVyIGFsdGVybmF0ZUlkZW50aWZpZXJUeXBlPSJhclhpdiI+MjIwNy4wNDc3OTwvYWx0ZXJuYXRlSWRlbnRpZmllcj4KICA8L2FsdGVybmF0ZUlkZW50aWZpZXJzPgogIDxjcmVhdG9ycz4KICAgIDxjcmVhdG9yPgogICAgICA8Y3JlYXRvck5hbWUgbmFtZVR5cGU9IlBlcnNvbmFsIj5CYXllciwgSm9uYXM8L2NyZWF0b3JOYW1lPgogICAgICA8Z2l2ZW5OYW1lPkpvbmFzPC9naXZlbk5hbWU+CiAgICAgIDxmYW1pbHlOYW1lPkJheWVyPC9mYW1pbHlOYW1lPgogICAgPC9jcmVhdG9yPgogICAgPGNyZWF0b3I+CiAgICAgIDxjcmVhdG9yTmFtZSBuYW1lVHlwZT0iUGVyc29uYWwiPkJlbnptw7xsbGVyLCBDaHJpc3RvcGg8L2NyZWF0b3JOYW1lPgogICAgICA8Z2l2ZW5OYW1lPkNocmlzdG9waDwvZ2l2ZW5OYW1lPgogICAgICA8ZmFtaWx5TmFtZT5CZW56bcO8bGxlcjwvZmFtaWx5TmFtZT4KICAgIDwvY3JlYXRvcj4KICAgIDxjcmVhdG9yPgogICAgICA8Y3JlYXRvck5hbWUgbmFtZVR5cGU9IlBlcnNvbmFsIj5CdXp6YXJkLCBLZXZpbjwvY3JlYXRvck5hbWU+CiAgICAgIDxnaXZlbk5hbWU+S2V2aW48L2dpdmVuTmFtZT4KICAgICAgPGZhbWlseU5hbWU+QnV6emFyZDwvZmFtaWx5TmFtZT4KICAgIDwvY3JlYXRvcj4KICAgIDxjcmVhdG9yPgogICAgICA8Y3JlYXRvck5hbWUgbmFtZVR5cGU9IlBlcnNvbmFsIj5EYXZpZCwgTWFyY288L2NyZWF0b3JOYW1lPgogICAgICA8Z2l2ZW5OYW1lPk1hcmNvPC9naXZlbk5hbWU+CiAgICAgIDxmYW1pbHlOYW1lPkRhdmlkPC9mYW1pbHlOYW1lPgogICAgPC9jcmVhdG9yPgogICAgPGNyZWF0b3I+CiAgICAgIDxjcmVhdG9yTmFtZSBuYW1lVHlwZT0iUGVyc29uYWwiPkxhbXBvcnQsIExlc2xpZTwvY3JlYXRvck5hbWU+CiAgICAgIDxnaXZlbk5hbWU+TGVzbGllPC9naXZlbk5hbWU+CiAgICAgIDxmYW1pbHlOYW1lPkxhbXBvcnQ8L2ZhbWlseU5hbWU+CiAgICA8L2NyZWF0b3I+CiAgICA8Y3JlYXRvcj4KICAgICAgPGNyZWF0b3JOYW1lIG5hbWVUeXBlPSJQZXJzb25hbCI+TWF0aXlhc2V2aWNoLCBZdXJpPC9jcmVhdG9yTmFtZT4KICAgICAgPGdpdmVuTmFtZT5ZdXJpPC9naXZlbk5hbWU+CiAgICAgIDxmYW1pbHlOYW1lPk1hdGl5YXNldmljaDwvZmFtaWx5TmFtZT4KICAgIDwvY3JlYXRvcj4KICAgIDxjcmVhdG9yPgogICAgICA8Y3JlYXRvck5hbWUgbmFtZVR5cGU9IlBlcnNvbmFsIj5QYXVsc29uLCBMYXdyZW5jZTwvY3JlYXRvck5hbWU+CiAgICAgIDxnaXZlbk5hbWU+TGF3cmVuY2U8L2dpdmVuTmFtZT4KICAgICAgPGZhbWlseU5hbWU+UGF1bHNvbjwvZmFtaWx5TmFtZT4KICAgIDwvY3JlYXRvcj4KICAgIDxjcmVhdG9yPgogICAgICA8Y3JlYXRvck5hbWUgbmFtZVR5cGU9IlBlcnNvbmFsIj5TY2hsZWljaGVyLCBEaWVyazwvY3JlYXRvck5hbWU+CiAgICAgIDxnaXZlbk5hbWU+RGllcms8L2dpdmVuTmFtZT4KICAgICAgPGZhbWlseU5hbWU+U2NobGVpY2hlcjwvZmFtaWx5TmFtZT4KICAgIDwvY3JlYXRvcj4KICAgIDxjcmVhdG9yPgogICAgICA8Y3JlYXRvck5hbWUgbmFtZVR5cGU9IlBlcnNvbmFsIj5TdG9jaywgQmVuZWRpa3Q8L2NyZWF0b3JOYW1lPgogICAgICA8Z2l2ZW5OYW1lPkJlbmVkaWt0PC9naXZlbk5hbWU+CiAgICAgIDxmYW1pbHlOYW1lPlN0b2NrPC9mYW1pbHlOYW1lPgogICAgPC9jcmVhdG9yPgogICAgPGNyZWF0b3I+CiAgICAgIDxjcmVhdG9yTmFtZSBuYW1lVHlwZT0iUGVyc29uYWwiPlplbG1hbm92LCBFZmltPC9jcmVhdG9yTmFtZT4KICAgICAgPGdpdmVuTmFtZT5FZmltPC9naXZlbk5hbWU+CiAgICAgIDxmYW1pbHlOYW1lPlplbG1hbm92PC9mYW1pbHlOYW1lPgogICAgPC9jcmVhdG9yPgogIDwvY3JlYXRvcnM+CiAgPHRpdGxlcz4KICAgIDx0aXRsZT5NYXRoZW1hdGljYWwgUHJvb2YgQmV0d2VlbiBHZW5lcmF0aW9uczwvdGl0bGU+CiAgPC90aXRsZXM+CiAgPHB1Ymxpc2hlcj5hclhpdjwvcHVibGlzaGVyPgogIDxwdWJsaWNhdGlvblllYXI+MjAyMjwvcHVibGljYXRpb25ZZWFyPgogIDxzdWJqZWN0cz4KICAgIDxzdWJqZWN0IHhtbDpsYW5nPSJlbiIgc3ViamVjdFNjaGVtZT0iYXJYaXYiPkhpc3RvcnkgYW5kIE92ZXJ2aWV3IChtYXRoLkhPKTwvc3ViamVjdD4KICAgIDxzdWJqZWN0IHhtbDpsYW5nPSJlbiIgc3ViamVjdFNjaGVtZT0iYXJYaXYiPkxvZ2ljIGluIENvbXB1dGVyIFNjaWVuY2UgKGNzLkxPKTwvc3ViamVjdD4KICAgIDxzdWJqZWN0IHN1YmplY3RTY2hlbWU9IkZpZWxkcyBvZiBTY2llbmNlIGFuZCBUZWNobm9sb2d5IChGT1MpIj5GT1M6IE1hdGhlbWF0aWNzPC9zdWJqZWN0PgogICAgPHN1YmplY3Qgc3ViamVjdFNjaGVtZT0iRmllbGRzIG9mIFNjaWVuY2UgYW5kIFRlY2hub2xvZ3kgKEZPUykiPkZPUzogQ29tcHV0ZXIgYW5kIGluZm9ybWF0aW9uIHNjaWVuY2VzPC9zdWJqZWN0PgogIDwvc3ViamVjdHM+CiAgPGRhdGVzPgogICAgPGRhdGUgZGF0ZVR5cGU9IlN1Ym1pdHRlZCIgZGF0ZUluZm9ybWF0aW9uPSJ2MSI+MjAyMi0wNy0wOFQxNDo0MjozM1o8L2RhdGU+CiAgICA8ZGF0ZSBkYXRlVHlwZT0iVXBkYXRlZCIgZGF0ZUluZm9ybWF0aW9uPSJ2MSI+MjAyMi0wNy0xM1QwMDoxNDoyNFo8L2RhdGU+CiAgICA8ZGF0ZSBkYXRlVHlwZT0iQXZhaWxhYmxlIiBkYXRlSW5mb3JtYXRpb249InYxIj4yMDIyLTA3PC9kYXRlPgogIDwvZGF0ZXM+CiAgPHJlc291cmNlVHlwZSByZXNvdXJjZVR5cGVHZW5lcmFsPSJQcmVwcmludCI+QXJ0aWNsZTwvcmVzb3VyY2VUeXBlPgogIDx2ZXJzaW9uPjE8L3ZlcnNpb24+CiAgPHJpZ2h0c0xpc3Q+CiAgICA8cmlnaHRzIHJpZ2h0c1VSST0iaHR0cDovL2FyeGl2Lm9yZy9saWNlbnNlcy9ub25leGNsdXNpdmUtZGlzdHJpYi8xLjAvIj5hclhpdi5vcmcgcGVycGV0dWFsLCBub24tZXhjbHVzaXZlIGxpY2Vuc2U8L3JpZ2h0cz4KICA8L3JpZ2h0c0xpc3Q+CiAgPGRlc2NyaXB0aW9ucz4KICAgIDxkZXNjcmlwdGlvbiBkZXNjcmlwdGlvblR5cGU9IkFic3RyYWN0Ij5BIHByb29mIGlzIG9uZSBvZiB0aGUgbW9zdCBpbXBvcnRhbnQgY29uY2VwdHMgb2YgbWF0aGVtYXRpY3MuIEhvd2V2ZXIsIHRoZXJlIGlzIGEgc3RyaWtpbmcgZGlmZmVyZW5jZSBiZXR3ZWVuIGhvdyBhIHByb29mIGlzIGRlZmluZWQgaW4gdGhlb3J5IGFuZCBob3cgaXQgaXMgdXNlZCBpbiBwcmFjdGljZS4gVGhpcyBwdXRzIHRoZSB1bmlxdWUgc3RhdHVzIG9mIG1hdGhlbWF0aWNzIGFzIGV4YWN0IHNjaWVuY2UgaW50byBwZXJpbC4gTm93IG1heSBiZSB0aGUgdGltZSB0byByZWNvbmNpbGUgdGhlb3J5IGFuZCBwcmFjdGljZSwgaS5lLiBwcmVjaXNpb24gYW5kIGludHVpdGlvbiwgdGhyb3VnaCB0aGUgYWR2ZW50IG9mIGNvbXB1dGVyIHByb29mIGFzc2lzdGFudHMuIEZvciB0aGUgbW9zdCB0aW1lIHRoaXMgaGFzIGJlZW4gYSB0b3BpYyBmb3IgZXhwZXJ0cyBpbiBzcGVjaWFsaXplZCBjb21tdW5pdGllcy4gSG93ZXZlciwgbWF0aGVtYXRpY2FsIHByb29mcyBoYXZlIGJlY29tZSBpbmNyZWFzaW5nbHkgc29waGlzdGljYXRlZCwgc3RyZXRjaGluZyB0aGUgYm91bmRhcmllcyBvZiB3aGF0IGlzIGh1bWFubHkgY29tcHJlaGVuc2libGUsIHNvIHRoYXQgbGVhZGluZyBtYXRoZW1hdGljaWFucyBoYXZlIGFza2VkIGZvciBmb3JtYWwgdmVyaWZpY2F0aW9uIG9mIHRoZWlyIHByb29mcy4gQXQgdGhlIHNhbWUgdGltZSwgbWFqb3IgdGhlb3JlbXMgaW4gbWF0aGVtYXRpY3MgaGF2ZSByZWNlbnRseSBiZWVuIGNvbXB1dGVyLXZlcmlmaWVkIGJ5IHBlb3BsZSBmcm9tIG91dHNpZGUgb2YgdGhlc2UgY29tbXVuaXRpZXMsIGV2ZW4gYnkgYmVnaW5uaW5nIHN0dWRlbnRzLiBUaGlzIGFydGljbGUgaW52ZXN0aWdhdGVzIHRoZSBnYXAgYmV0d2VlbiB0aGUgZGlmZmVyZW50IGRlZmluaXRpb25zIG9mIGEgcHJvb2YgYW5kIHBvc3NpYmlsaXRpZXMgdG8gYnVpbGQgYnJpZGdlcy4gSXQgaXMgd3JpdHRlbiBhcyBhIHBvbGVtaWMgb3IgYSBjb2xsYWdlIGJ5IGRpZmZlcmVudCBtZW1iZXJzIG9mIHRoZSBjb21tdW5pdGllcyBpbiBtYXRoZW1hdGljcyBhbmQgY29tcHV0ZXIgc2NpZW5jZSBhdCBkaWZmZXJlbnQgc3RhZ2VzIG9mIHRoZWlyIGNhcmVlcnMsIGNoYWxsZW5naW5nIHdlbGwta25vd24gcHJlY29uY2VwdGlvbnMgYW5kIGV4cGxvcmluZyBuZXcgcGVyc3BlY3RpdmVzLjwvZGVzY3JpcHRpb24+CiAgICA8ZGVzY3JpcHRpb24gZGVzY3JpcHRpb25UeXBlPSJPdGhlciI+MTcgcGFnZXMsIDEgZmlndXJlPC9kZXNjcmlwdGlvbj4KICA8L2Rlc2NyaXB0aW9ucz4KPC9yZXNvdXJjZT4=","url":"https://arxiv.org/abs/2207.04779","contentUrl":null,"metadataVersion":1,"schemaVersion":"http://datacite.org/schema/kernel-4","source":"mds","isActive":true,"state":"findable","reason":null,"viewCount":0,"viewsOverTime":[],"downloadCount":0,"downloadsOverTime":[],"referenceCount":0,"citationCount":0,"citationsOverTime":[],"partCount":0,"partOfCount":0,"versionCount":0,"versionOfCount":0,"created":"2022-07-12T01:41:56.000Z","registered":"2022-07-12T01:41:57.000Z","published":"2022","updated":"2022-07-13T01:24:20.000Z"},"relationships":{"client":{"data":{"id":"arxiv.content","type":"clients"}},"provider":{"data":{"id":"arxiv","type":"providers"}},"media":{"data":{"id":"10.48550/arxiv.2207.04779","type":"media"}},"references":{"data":[]},"citations":{"data":[]},"parts":{"data":[]},"partOf":{"data":[]},"versions":{"data":[]},"versionOf":{"data":[]}}}} diff --git a/dspace/config/spring/api/datacite-integration.xml b/dspace/config/spring/api/datacite-integration.xml index e1efa3eadbd9..609f49d111ed 100644 --- a/dspace/config/spring/api/datacite-integration.xml +++ b/dspace/config/spring/api/datacite-integration.xml @@ -24,8 +24,13 @@ + + + + + + -