diff --git a/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/SimpleRisToMetadataConcatContributor.java b/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/SimpleRisToMetadataConcatContributor.java new file mode 100644 index 0000000000..5dd354c6f1 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/SimpleRisToMetadataConcatContributor.java @@ -0,0 +1,59 @@ +/** + * 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.importer.external.metadatamapping.contributor; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.dspace.importer.external.metadatamapping.MetadataFieldConfig; +import org.dspace.importer.external.metadatamapping.MetadatumDTO; + +/** + * This contributor extends SimpleRisToMetadataContributor, + * in particular, this one is able to chain multi values into a single one + * + * @author Mykhaylo Boychuk (mykhaylo.boychuk at 4science.it) + */ +public class SimpleRisToMetadataConcatContributor extends SimpleRisToMetadataContributor { + + private String tag; + + private MetadataFieldConfig metadata; + + @Override + public Collection contributeMetadata(Map> record) { + List values = new LinkedList<>(); + List fieldValues = record.get(this.tag); + Optional.ofNullable(fieldValues) + .map(fv -> fv.stream()) + .map(s -> s.collect(Collectors.joining(" "))) + .ifPresent(t -> values.add(this.metadataFieldMapping.toDCValue(this.metadata, t))); + return values; + } + + public String getTag() { + return tag; + } + + public void setTag(String tag) { + this.tag = tag; + } + + public MetadataFieldConfig getMetadata() { + return metadata; + } + + public void setMetadata(MetadataFieldConfig metadata) { + this.metadata = metadata; + } + +} \ No newline at end of file diff --git a/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/SimpleRisToMetadataContributor.java b/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/SimpleRisToMetadataContributor.java new file mode 100644 index 0000000000..36ea0dd478 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/SimpleRisToMetadataContributor.java @@ -0,0 +1,71 @@ +/** + * 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.importer.external.metadatamapping.contributor; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import org.dspace.importer.external.metadatamapping.MetadataFieldConfig; +import org.dspace.importer.external.metadatamapping.MetadataFieldMapping; +import org.dspace.importer.external.metadatamapping.MetadatumDTO; + +/** + * Metadata contributor that takes a record defined as Map> + * and turns it into metadatums configured in fieldToMetadata + * + * @author Mykhaylo Boychuk (mykhaylo.boychuk at 4science.it) + */ +public class SimpleRisToMetadataContributor implements MetadataContributor>> { + + protected Map fieldToMetadata; + + protected MetadataFieldMapping>, + MetadataContributor>>> metadataFieldMapping; + + public SimpleRisToMetadataContributor() {} + + public SimpleRisToMetadataContributor(Map fieldToMetadata) { + this.fieldToMetadata = fieldToMetadata; + } + + @Override + public Collection contributeMetadata(Map> record) { + List values = new LinkedList<>(); + for (String field : fieldToMetadata.keySet()) { + List fieldValues = record.get(field); + if (Objects.nonNull(fieldValues)) { + for (String value : fieldValues) { + values.add(metadataFieldMapping.toDCValue(fieldToMetadata.get(field), value)); + } + } + } + return values; + } + + public Map getFieldToMetadata() { + return fieldToMetadata; + } + + public void setFieldToMetadata(Map fieldToMetadata) { + this.fieldToMetadata = fieldToMetadata; + } + + public MetadataFieldMapping>, + MetadataContributor>>> getMetadataFieldMapping() { + return metadataFieldMapping; + } + + public void setMetadataFieldMapping(MetadataFieldMapping>, + MetadataContributor>>> metadataFieldMapping) { + this.metadataFieldMapping = metadataFieldMapping; + } + +} \ No newline at end of file diff --git a/dspace-api/src/main/java/org/dspace/importer/external/scielo/service/ScieloFieldMapping.java b/dspace-api/src/main/java/org/dspace/importer/external/scielo/service/ScieloFieldMapping.java new file mode 100644 index 0000000000..0d7183a1f0 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/importer/external/scielo/service/ScieloFieldMapping.java @@ -0,0 +1,37 @@ +/** + * 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.importer.external.scielo.service; +import java.util.Map; +import javax.annotation.Resource; + +import org.dspace.importer.external.metadatamapping.AbstractMetadataFieldMapping; + +/** + * An implementation of {@link AbstractMetadataFieldMapping} + * Responsible for defining the mapping of the Scielo metadatum fields on the DSpace metadatum fields + * + * @author Boychuk Mykhaylo (boychuk.mykhaylo at 4science dot it) + */ +@SuppressWarnings("rawtypes") +public class ScieloFieldMapping extends AbstractMetadataFieldMapping { + + /** + * Defines which metadatum is mapped on which metadatum. Note that while the key must be unique it + * only matters here for postprocessing of the value. The mapped MetadatumContributor has full control over + * what metadatafield is generated. + * + * @param metadataFieldMap The map containing the link between retrieve metadata and + * metadata that will be set to the item. + */ + @Override + @SuppressWarnings("unchecked") + @Resource(name = "scieloMetadataFieldMap") + public void setMetadataFieldMap(Map metadataFieldMap) { + super.setMetadataFieldMap(metadataFieldMap); + } +} \ No newline at end of file diff --git a/dspace-api/src/main/java/org/dspace/importer/external/scielo/service/ScieloImportMetadataSourceServiceImpl.java b/dspace-api/src/main/java/org/dspace/importer/external/scielo/service/ScieloImportMetadataSourceServiceImpl.java new file mode 100644 index 0000000000..66dc574e63 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/importer/external/scielo/service/ScieloImportMetadataSourceServiceImpl.java @@ -0,0 +1,263 @@ +/** + * 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.importer.external.scielo.service; + +import java.io.BufferedReader; +import java.io.StringReader; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.Callable; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.el.MethodNotFoundException; +import javax.ws.rs.BadRequestException; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.http.client.utils.URIBuilder; +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.FileSourceException; +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.components.QuerySource; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * Implements a data source for querying Scielo + * + * @author Boychuk Mykhaylo (boychuk.mykhaylo at 4Science dot it) + */ +public class ScieloImportMetadataSourceServiceImpl extends AbstractImportMetadataSourceService>> + implements QuerySource { + + /** + * This pattern is used when reading the Scielo response, + * to check if the fields you are reading is in rid format + */ + private static final String PATTERN = "^([A-Z][A-Z0-9]) - (.*)$"; + + /** + * This pattern is used to verify correct format of ScieloId + */ + private static final String ID_PATTERN = "^(.....)-(.*)-(...)$"; + + private int timeout = 1000; + + private String url; + + @Autowired + private LiveImportClient liveImportClient; + + @Override + public void init() throws Exception {} + + @Override + public String getImportSource() { + return "scielo"; + } + + @Override + public Collection getRecords(String query, int start, int count) throws MetadataSourceException { + return retry(new SearchByQueryCallable(query, count, start)); + } + + @Override + public Collection getRecords(Query query) throws MetadataSourceException { + return retry(new SearchByQueryCallable(query)); + } + + + @Override + public ImportRecord getRecord(Query query) throws MetadataSourceException { + List records = retry(new SearchByQueryCallable(query)); + return CollectionUtils.isEmpty(records) ? null : records.get(0); + } + + @Override + public ImportRecord getRecord(String id) throws MetadataSourceException { + List records = retry(new FindByIdCallable(id)); + return CollectionUtils.isEmpty(records) ? null : records.get(0); + } + + @Override + public int getRecordsCount(String query) throws MetadataSourceException { + return retry(new SearchNBByQueryCallable(query)); + } + + @Override + public int getRecordsCount(Query query) throws MetadataSourceException { + throw new MethodNotFoundException("This method is not implemented for Scielo"); + } + + @Override + public Collection findMatchingRecords(Item item) throws MetadataSourceException { + throw new MethodNotFoundException("This method is not implemented for Scielo"); + } + + @Override + public Collection findMatchingRecords(Query query) throws MetadataSourceException { + throw new MethodNotFoundException("This method is not implemented for Scielo"); + } + + /** + * This class is a Callable implementation to count the number of entries for an Scielo query + * + * @author Mykhaylo Boychuk (mykhaylo.boychuk@4science.com) + */ + private class SearchNBByQueryCallable implements Callable { + + private String query; + + private SearchNBByQueryCallable(String queryString) { + this.query = queryString; + } + + private SearchNBByQueryCallable(Query query) { + this.query = query.getParameterAsClass("query", String.class); + } + + @Override + public Integer call() throws Exception { + URIBuilder uriBuilder = new URIBuilder(url + URLEncoder.encode(query, StandardCharsets.UTF_8)); + String resp = liveImportClient.executeHttpGetRequest(timeout, uriBuilder.toString(), + new HashMap()); + Map>> records = getRecords(resp); + return Objects.nonNull(records.size()) ? records.size() : 0; + } + } + + /** + * This class is a Callable implementation to get an Scielo entry using ScieloID + * The ScieloID to use can be passed through the constructor as a String + * or as Query's map entry, with the key "id". + * + * @author Mykhaylo Boychuk (mykhaylo.boychuk@4science.com) + */ + private class FindByIdCallable implements Callable> { + + private String id; + + private FindByIdCallable(String id) { + this.id = id; + } + + @Override + public List call() throws Exception { + List results = new ArrayList<>(); + String scieloId = id.trim(); + Pattern risPattern = Pattern.compile(ID_PATTERN); + Matcher risMatcher = risPattern.matcher(scieloId); + if (risMatcher.matches()) { + URIBuilder uriBuilder = new URIBuilder(url + URLEncoder.encode(scieloId, StandardCharsets.UTF_8)); + String resp = liveImportClient.executeHttpGetRequest(timeout, uriBuilder.toString(), + new HashMap()); + Map>> records = getRecords(resp); + if (Objects.nonNull(records) & !records.isEmpty()) { + results.add(transformSourceRecords(records.get(1))); + } + } else { + throw new BadRequestException("id provided : " + scieloId + " is not an ScieloID"); + } + return results; + } + } + + /** + * This class is a Callable implementation to get Scielo entries based on query object. + * This Callable use as query value the string queryString passed to constructor. + * If the object will be construct through Query.class instance, a Query's map entry with key "query" will be used. + * Pagination is supported too, using the value of the Query's map with keys "start" and "count". + * + * @author Mykhaylo Boychuk (mykhaylo.boychuk@4science.com) + */ + 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("start", start); + query.addParameter("count", maxResult); + } + + private SearchByQueryCallable(Query query) { + this.query = query; + } + + @Override + public List call() throws Exception { + List results = new ArrayList<>(); + String q = query.getParameterAsClass("query", String.class); + Integer count = query.getParameterAsClass("count", Integer.class); + Integer start = query.getParameterAsClass("start", Integer.class); + URIBuilder uriBuilder = new URIBuilder(url + URLEncoder.encode(q, StandardCharsets.UTF_8)); + uriBuilder.addParameter("start", start.toString()); + uriBuilder.addParameter("count", count.toString()); + String resp = liveImportClient.executeHttpGetRequest(timeout, uriBuilder.toString(), + new HashMap()); + Map>> records = getRecords(resp); + for (int record : records.keySet()) { + results.add(transformSourceRecords(records.get(record))); + } + return results; + } + } + + private Map>> getRecords(String resp) throws FileSourceException { + Map>> records = new HashMap>>(); + BufferedReader reader; + int countRecord = 0; + try { + reader = new BufferedReader(new StringReader(resp)); + String line; + while ((line = reader.readLine()) != null) { + if (line.isEmpty() || line.equals("") || line.matches("^\\s*$")) { + continue; + } + line = line.replaceAll("\\uFEFF", "").trim(); + Pattern risPattern = Pattern.compile(PATTERN); + Matcher risMatcher = risPattern.matcher(line); + if (risMatcher.matches()) { + if (risMatcher.group(1).equals("TY") & risMatcher.group(2).equals("JOUR")) { + countRecord ++; + Map> newMap = new HashMap>(); + records.put(countRecord, newMap); + } else { + Map> tag2values = records.get(countRecord); + List values = tag2values.get(risMatcher.group(1)); + if (Objects.isNull(values)) { + List newValues = new ArrayList(); + newValues.add(risMatcher.group(2)); + tag2values.put(risMatcher.group(1), newValues); + } else { + values.add(risMatcher.group(2)); + tag2values.put(risMatcher.group(1), values); + } + } + } + } + } catch (Exception e) { + throw new FileSourceException("Cannot parse RIS file", e); + } + return records; + } + + public void setUrl(String url) { + this.url = url; + } + +} \ No newline at end of file diff --git a/dspace-api/src/main/java/org/dspace/importer/external/service/DoiCheck.java b/dspace-api/src/main/java/org/dspace/importer/external/service/DoiCheck.java index 3b15a421b8..95d42e3a27 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/service/DoiCheck.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/service/DoiCheck.java @@ -13,7 +13,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; /** - * Utility class that provides methods to check if a given string is a DOI and exists on CrossRef services + * Utility class that provides methods to check if a given string is a DOI * * @author Corrado Lombardi (corrado.lombardi at 4science.it) */ diff --git a/dspace-api/src/main/resources/spring/spring-dspace-addon-import-services.xml b/dspace-api/src/main/resources/spring/spring-dspace-addon-import-services.xml index 787f64b68c..b704ba085b 100644 --- a/dspace-api/src/main/resources/spring/spring-dspace-addon-import-services.xml +++ b/dspace-api/src/main/resources/spring/spring-dspace-addon-import-services.xml @@ -130,6 +130,12 @@ + + + + + + diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ScieloImportMetadataSourceServiceIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ScieloImportMetadataSourceServiceIT.java new file mode 100644 index 0000000000..aafc75a065 --- /dev/null +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ScieloImportMetadataSourceServiceIT.java @@ -0,0 +1,236 @@ +/** + * 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.junit.Assert.assertNotNull; +import static org.mockito.Mockito.when; + +import java.io.InputStream; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Arrays; +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.datamodel.ImportRecord; +import org.dspace.importer.external.datamodel.Query; +import org.dspace.importer.external.liveimportclient.service.LiveImportClientImpl; +import org.dspace.importer.external.metadatamapping.MetadatumDTO; +import org.dspace.importer.external.scielo.service.ScieloImportMetadataSourceServiceImpl; +import org.junit.Test; +import org.mockito.ArgumentMatchers; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * Integration tests for {@link ScieloImportMetadataSourceServiceImpl} + * + * @author Mykhaylo Boychuk (mykhaylo.boychuk at 4science.com) + */ +public class ScieloImportMetadataSourceServiceIT extends AbstractLiveImportIntegrationTest { + + @Autowired + private LiveImportClientImpl liveImportClientImpl; + + @Autowired + private ScieloImportMetadataSourceServiceImpl scieloServiceImpl; + + @Test + public void scieloImportMetadataGetRecordsTest() throws Exception { + context.turnOffAuthorisationSystem(); + CloseableHttpClient originalHttpClient = liveImportClientImpl.getHttpClient(); + CloseableHttpClient httpClient = Mockito.mock(CloseableHttpClient.class); + try (InputStream scieloResp = getClass().getResourceAsStream("scielo-test.txt")) { + + String scieloRipResp = IOUtils.toString(scieloResp, Charset.defaultCharset()); + + liveImportClientImpl.setHttpClient(httpClient); + CloseableHttpResponse response = mockResponse(scieloRipResp, 200, "OK"); + when(httpClient.execute(ArgumentMatchers.any())).thenReturn(response); + + context.restoreAuthSystemState(); + ArrayList collection2match = getRecords(); + Collection recordsImported = scieloServiceImpl.getRecords("test query", 0, 2); + assertEquals(2, recordsImported.size()); + matchRecords(new ArrayList(recordsImported), collection2match); + } finally { + liveImportClientImpl.setHttpClient(originalHttpClient); + } + } + + @Test + public void scieloImportMetadataGetRecordsCountTest() throws Exception { + context.turnOffAuthorisationSystem(); + CloseableHttpClient originalHttpClient = liveImportClientImpl.getHttpClient(); + CloseableHttpClient httpClient = Mockito.mock(CloseableHttpClient.class); + try (InputStream file = getClass().getResourceAsStream("scielo-test.txt")) { + String scieloResp = IOUtils.toString(file, Charset.defaultCharset()); + + liveImportClientImpl.setHttpClient(httpClient); + CloseableHttpResponse response = mockResponse(scieloResp, 200, "OK"); + when(httpClient.execute(ArgumentMatchers.any())).thenReturn(response); + + context.restoreAuthSystemState(); + int tot = scieloServiceImpl.getRecordsCount("test query"); + assertEquals(2, tot); + } finally { + liveImportClientImpl.setHttpClient(originalHttpClient); + } + } + + @Test(expected = MethodNotFoundException.class) + public void scieloImportMetadataFindMatchingRecordsTest() 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(); + scieloServiceImpl.findMatchingRecords(testItem); + } + + @Test(expected = MethodNotFoundException.class) + public void scieloImportMetadataGetRecordsCountByQueryTest() throws Exception { + Query q = new Query(); + q.addParameter("query", "test query"); + scieloServiceImpl.getRecordsCount(q); + } + + @Test + public void scieloImportMetadataGetRecordsByIdTest() throws Exception { + context.turnOffAuthorisationSystem(); + CloseableHttpClient originalHttpClient = liveImportClientImpl.getHttpClient(); + CloseableHttpClient httpClient = Mockito.mock(CloseableHttpClient.class); + try (InputStream scieloResp = getClass().getResourceAsStream("scielo-single-record.txt")) { + + String scieloRipResp = IOUtils.toString(scieloResp, Charset.defaultCharset()); + + liveImportClientImpl.setHttpClient(httpClient); + CloseableHttpResponse response = mockResponse(scieloRipResp, 200, "OK"); + when(httpClient.execute(ArgumentMatchers.any())).thenReturn(response); + + context.restoreAuthSystemState(); + ArrayList collection2match = getRecords(); + collection2match.remove(1); + ImportRecord record = scieloServiceImpl.getRecord("S0185-30582021000200231-mex"); + assertNotNull(record); + Collection recordsImported = Arrays.asList(record); + matchRecords(new ArrayList(recordsImported), collection2match); + } finally { + liveImportClientImpl.setHttpClient(originalHttpClient); + } + } + + private ArrayList getRecords() { + ArrayList records = new ArrayList<>(); + //define first record + List metadatums = new ArrayList(); + MetadatumDTO ispartof = createMetadatumDTO("dc", "relation", "ispartof", "Nova tellus"); + MetadatumDTO date = createMetadatumDTO("dc", "date", "issued", "2021"); + MetadatumDTO citation = createMetadatumDTO("oaire", "citation", "issue", "2"); + MetadatumDTO doi = createMetadatumDTO("dc", "identifier", "doi", "10.19130/iifl.nt.2021.39.2.901"); + MetadatumDTO endPage = createMetadatumDTO("oaire", "citation", "endPage", "236"); + MetadatumDTO subject = createMetadatumDTO("dc", "subject", null, "Roma"); + MetadatumDTO subject2 = createMetadatumDTO("dc", "subject", null, "Historia"); + MetadatumDTO subject3 = createMetadatumDTO("dc", "subject", null, "ritos funerarios"); + MetadatumDTO subject4 = createMetadatumDTO("dc", "subject", null, "inframundo"); + MetadatumDTO subject5 = createMetadatumDTO("dc", "subject", null, "epitafios"); + MetadatumDTO author = createMetadatumDTO("dc", "contributor", "author", "Torres Marzo, Ricardo"); + MetadatumDTO title = createMetadatumDTO("dc", "title", null, "Requena Jiménez, Miguel, Los espacios" + + " de la muerte en Roma, Madrid, Síntesis, 2021, 365 págs." + + " más bibliografía en línea, ISBN 978-84-135759-6-4."); + MetadatumDTO volume = createMetadatumDTO("oaire", "citation", "volume", "39"); + MetadatumDTO issn = createMetadatumDTO("dc", "identifier", "issn", "0185-3058"); + MetadatumDTO other = createMetadatumDTO("dc", "identifier", "other", "S0185-30582021000200231-mex"); + MetadatumDTO startPage = createMetadatumDTO("oaire", "citation", "startPage", "231"); + + metadatums.add(ispartof); + metadatums.add(date); + metadatums.add(citation); + metadatums.add(doi); + metadatums.add(endPage); + metadatums.add(subject); + metadatums.add(subject2); + metadatums.add(subject3); + metadatums.add(subject4); + metadatums.add(subject5); + metadatums.add(author); + metadatums.add(title); + metadatums.add(volume); + metadatums.add(issn); + metadatums.add(other); + metadatums.add(startPage); + + ImportRecord firstrRecord = new ImportRecord(metadatums); + + //define second record + List metadatums2 = new ArrayList(); + MetadatumDTO ispartof2 = createMetadatumDTO("dc", "relation", "ispartof", "Revista de Derecho Privado"); + MetadatumDTO date2 = createMetadatumDTO("dc", "date", "issued", "2021"); + MetadatumDTO citation2 = createMetadatumDTO("oaire", "citation", "issue", "41"); + MetadatumDTO doi2 = createMetadatumDTO("dc", "identifier", "doi", "10.18601/01234366.n41.14"); + MetadatumDTO endPage2 = createMetadatumDTO("oaire", "citation", "endPage", "418"); + MetadatumDTO subject6 = createMetadatumDTO("dc", "subject", null, "sopravvenienza contrattuale"); + MetadatumDTO subject7 = createMetadatumDTO("dc", "subject", null, "covro"); + MetadatumDTO subject8 = createMetadatumDTO("dc", "subject", null, "buona fede in senso oggettivo"); + MetadatumDTO subject9 = createMetadatumDTO("dc", "subject", null, "obbligo di rinegoziare"); + MetadatumDTO subject10 = createMetadatumDTO("dc", "subject", null, "revisione del contratto"); + MetadatumDTO author2 = createMetadatumDTO("dc", "contributor", "author", "MAGRI, GEO"); + MetadatumDTO title2 = createMetadatumDTO("dc", "title", null, + "Rinegoziazione e revisione del contratto. Tribunale di Roma, Sez. VI, 27 agosto 2020"); + MetadatumDTO issn2 = createMetadatumDTO("dc", "identifier", "issn", "0123-4366"); + MetadatumDTO other2 = createMetadatumDTO("dc", "identifier", "other", "S0123-43662021000200397-col"); + MetadatumDTO startPage2 = createMetadatumDTO("oaire", "citation", "startPage", "397"); + MetadatumDTO description = createMetadatumDTO("dc", "description", "abstract", + "ABSTRACT: The Tribunal of Rome imposes an obligation to renegotiate long-term contracts," + + " the balance of which has been modified by the covro pandemic. The decision establishes a" + + " general obligation for the parties to execute the contract in good faith and gives the judge" + + " the possibility of a judicial review. This is a long-awaited decision in doctrine which complies" + + " with the indications of the Supreme Court of Cassation expressed in its memorandum 56/2020."); + + metadatums2.add(ispartof2); + metadatums2.add(date2); + metadatums2.add(citation2); + metadatums2.add(doi2); + metadatums2.add(endPage2); + metadatums2.add(subject6); + metadatums2.add(subject7); + metadatums2.add(subject8); + metadatums2.add(subject9); + metadatums2.add(subject10); + metadatums2.add(author2); + metadatums2.add(title2); + metadatums2.add(issn2); + metadatums2.add(other2); + metadatums2.add(startPage2); + metadatums2.add(description); + + ImportRecord secondRecord = new ImportRecord(metadatums2); + records.add(firstrRecord); + records.add(secondRecord); + return records; + } + +} \ No newline at end of file diff --git a/dspace-server-webapp/src/test/resources/org/dspace/app/rest/scielo-single-record.txt b/dspace-server-webapp/src/test/resources/org/dspace/app/rest/scielo-single-record.txt new file mode 100644 index 0000000000..bd9934d2bc --- /dev/null +++ b/dspace-server-webapp/src/test/resources/org/dspace/app/rest/scielo-single-record.txt @@ -0,0 +1,24 @@ +TY - JOUR +AU - Torres Marzo, Ricardo +TI - Requena Jiménez, Miguel, Los espacios de la muerte en Roma, Madrid, Síntesis, 2021, 365 págs. más bibliografía en línea, ISBN 978-84-135759-6-4. +JO - Nova tellus +J2 - Nova tellus +SN - 0185-3058 +VL - 39 +IS - 2 +DO - 10.19130/iifl.nt.2021.39.2.901 +DB - SciELO México +DP - http://www.scielo.org/ +ID - S0185-30582021000200231-mex +LA - es +SP - 231 +EP - 236 +DA - 2021-12 +PY - 2021 +UR - http://www.scielo.org.mx/scielo.php?script=sci_arttext&pid=S0185-30582021000200231&lang=pt +KW - Roma +KW - Historia +KW - ritos funerarios +KW - inframundo +KW - epitafios +ER - \ No newline at end of file diff --git a/dspace-server-webapp/src/test/resources/org/dspace/app/rest/scielo-test.txt b/dspace-server-webapp/src/test/resources/org/dspace/app/rest/scielo-test.txt new file mode 100644 index 0000000000..4cc9d3ad36 --- /dev/null +++ b/dspace-server-webapp/src/test/resources/org/dspace/app/rest/scielo-test.txt @@ -0,0 +1,51 @@ +TY - JOUR +AU - Torres Marzo, Ricardo +TI - Requena Jiménez, Miguel, Los espacios de la muerte en Roma, Madrid, Síntesis, 2021, 365 págs. más bibliografía en línea, ISBN 978-84-135759-6-4. +JO - Nova tellus +J2 - Nova tellus +SN - 0185-3058 +VL - 39 +IS - 2 +DO - 10.19130/iifl.nt.2021.39.2.901 +DB - SciELO México +DP - http://www.scielo.org/ +ID - S0185-30582021000200231-mex +LA - es +SP - 231 +EP - 236 +DA - 2021-12 +PY - 2021 +UR - http://www.scielo.org.mx/scielo.php?script=sci_arttext&pid=S0185-30582021000200231&lang=pt +KW - Roma +KW - Historia +KW - ritos funerarios +KW - inframundo +KW - epitafios +ER - + +TY - JOUR +AU - MAGRI, GEO +TI - Rinegoziazione e revisione del contratto. Tribunale di Roma, Sez. VI, 27 agosto 2020 +JO - Revista de Derecho Privado +J2 - Rev. Derecho Privado +SN - 0123-4366 +VL - +IS - 41 +DO - 10.18601/01234366.n41.14 +DB - SciELO Colômbia +DP - http://www.scielo.org/ +ID - S0123-43662021000200397-col +LA - it +SP - 397 +EP - 418 +DA - 2021-12 +PY - 2021 +AB - ABSTRACT: The Tribunal of Rome imposes an obligation to renegotiate long-term contracts, the balance of which has been modified by the covro pandemic. The decision establishes a general obligation for the parties to execute the contract in good faith and gives the judge the possibility of a judicial review. This is a long-awaited decision in doctrine which complies with the indications of the Supreme Court of Cassation expressed in its memorandum 56/2020. +UR - http://www.scielo.org.co/scielo.php?script=sci_arttext&pid=S0123-43662021000200397&lang=pt +L1 - http://www.scielo.org.co/pdf/rdp/n41/0123-4366-rdp-41-397.pdf +KW - sopravvenienza contrattuale +KW - covro +KW - buona fede in senso oggettivo +KW - obbligo di rinegoziare +KW - revisione del contratto +ER - \ No newline at end of file diff --git a/dspace/config/modules/external-providers.cfg b/dspace/config/modules/external-providers.cfg index dbefd93ff1..f5e38fdee3 100644 --- a/dspace/config/modules/external-providers.cfg +++ b/dspace/config/modules/external-providers.cfg @@ -19,4 +19,10 @@ crossref.url = https://api.crossref.org/works vufind.url = https://vufind.org/advanced_demo/api/v1/record vufind.url.search = https://vufind.org/advanced_demo/api/v1/search +################################################################# +#---------------------- Scielo -----------------------------# +#---------------------------------------------------------------# + +scielo.url = https://search.scielo.org/?output=ris&q= + ################################################################# \ No newline at end of file diff --git a/dspace/config/spring/api/external-services.xml b/dspace/config/spring/api/external-services.xml index d12b973a3b..60158a8512 100644 --- a/dspace/config/spring/api/external-services.xml +++ b/dspace/config/spring/api/external-services.xml @@ -118,4 +118,15 @@ + + + + + + + Publication + + + + \ No newline at end of file diff --git a/dspace/config/spring/api/scielo-integration.xml b/dspace/config/spring/api/scielo-integration.xml new file mode 100644 index 0000000000..05ee62c9c1 --- /dev/null +++ b/dspace/config/spring/api/scielo-integration.xml @@ -0,0 +1,109 @@ + + + + + + + Defines which metadatum is mapped on which metadatum. Note that while the key must be unique it + only matters here for postprocessing of the value. The mapped MetadatumContributor has full control over + what metadatafield is generated. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file