From e59be9f528d283de104f76ba2d32f66e24864798 Mon Sep 17 00:00:00 2001 From: milanmajchrak Date: Fri, 24 May 2024 13:47:40 +0200 Subject: [PATCH 1/4] Created method which updates properly the Item's date metadata. --- .../content/clarin/ClarinItemServiceImpl.java | 62 ++++++++++++ .../service/clarin/ClarinItemService.java | 11 +++ .../app/rest/converter/ItemConverter.java | 27 +++--- .../dspace/app/rest/ItemRestRepositoryIT.java | 94 +++++++++++++------ 4 files changed, 148 insertions(+), 46 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/clarin/ClarinItemServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/clarin/ClarinItemServiceImpl.java index 1538f7513be9..0d9758f5c101 100644 --- a/dspace-api/src/main/java/org/dspace/content/clarin/ClarinItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/clarin/ClarinItemServiceImpl.java @@ -8,11 +8,14 @@ package org.dspace.content.clarin; import java.sql.SQLException; +import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.UUID; import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.math.NumberUtils; import org.apache.logging.log4j.Logger; import org.dspace.content.Bitstream; import org.dspace.content.Bundle; @@ -21,12 +24,14 @@ import org.dspace.content.DSpaceObject; import org.dspace.content.Item; import org.dspace.content.MetadataField; +import org.dspace.content.MetadataValue; import org.dspace.content.dao.clarin.ClarinItemDAO; import org.dspace.content.service.CollectionService; import org.dspace.content.service.ItemService; import org.dspace.content.service.clarin.ClarinItemService; import org.dspace.core.Constants; import org.dspace.core.Context; +import org.dspace.services.RequestService; import org.springframework.beans.factory.annotation.Autowired; /** @@ -38,6 +43,9 @@ public class ClarinItemServiceImpl implements ClarinItemService { private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(ClarinItemServiceImpl.class); + private static final String DELIMETER = ","; + private static final String NO_YEAR = "0000"; + @Autowired ClarinItemDAO clarinItemDAO; @@ -203,4 +211,58 @@ public void updateItemFilesMetadata(Context context, Bitstream bit) throws SQLEx } this.updateItemFilesMetadata(context, item, bundle); } + + @Override + public void updateItemDatesMetadata(Context context, Item item) throws SQLException { + List approximatedDates = + itemService.getMetadata(item, "local", "approximateDate", "issued", Item.ANY, false); + + if(CollectionUtils.isEmpty(approximatedDates) || StringUtils.isBlank(approximatedDates.get(0).getValue())) { + log.warn("Cannot update item dates metadata because the approximate date is empty."); + return; + } + + // Get the approximate date value from the metadata + String approximateDateValue = approximatedDates.get(0).getValue(); + + // Split the approximate date value by the delimeter and get the list of years. + List listOfYearValues = Arrays.asList(approximateDateValue.split(DELIMETER)); + // Trim the list of years - remove leading and trailing whitespaces + listOfYearValues.replaceAll(String::trim); + + try { + // Clear the current `dc.date.issued` metadata + itemService.clearMetadata(context, item, "dc", "date", "issued", Item.ANY); + + // Update the `dc.date.issued` metadata with a new value: `0000` or the last year from the sequence + if (CollectionUtils.isNotEmpty(listOfYearValues) && isListOfNumbers(listOfYearValues)) { + // Take the last year from the list of years and add it to the `dc.date.issued` metadata + itemService.addMetadata(context, item, "dc", "date", "issued", Item.ANY, + getLastNumber(listOfYearValues)); + } else { + // Add the `0000` value to the `dc.date.issued` metadata + itemService.addMetadata(context, item, "dc", "date", "issued", Item.ANY, NO_YEAR); + } + } catch (SQLException e) { + log.error("Cannot remove `dc.date.issued` metadata because: {}", e.getMessage()); + } + } + + public static boolean isListOfNumbers(List values) { + for (String value : values) { + if (!NumberUtils.isCreatable(value)) { + return false; + } + } + return true; + } + + private static String getLastNumber(List values) { + if (CollectionUtils.isEmpty(values)) { + return NO_YEAR; + } + return values.get(values.size() - 1); + } + + } diff --git a/dspace-api/src/main/java/org/dspace/content/service/clarin/ClarinItemService.java b/dspace-api/src/main/java/org/dspace/content/service/clarin/ClarinItemService.java index 6595662c9e9b..de481db968fd 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/clarin/ClarinItemService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/clarin/ClarinItemService.java @@ -90,4 +90,15 @@ public interface ClarinItemService { */ void updateItemFilesMetadata(Context context, Bitstream bit) throws SQLException; + /** + * Update item's metadata about its dates (dc.date.issued, local.approximateDate.issued). + * If the local.approximateDate.issued has a value like 'cca 1938 - 1945' or something else, + * then dc.date.issued = 0000. + * If the local.approximateDate.issued has a value like '1938, 1945, 2022', then dc.date.issued = 2022. + * + * @param context DSpace context object + * @param item Update metadata for this Item + */ + void updateItemDatesMetadata(Context context, Item item) throws SQLException; + } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ItemConverter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ItemConverter.java index 433c15363c05..dd71cb3a26d8 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ItemConverter.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ItemConverter.java @@ -19,13 +19,14 @@ import org.dspace.app.rest.model.ItemRest; import org.dspace.app.rest.model.MetadataValueList; import org.dspace.app.rest.projection.Projection; -import org.dspace.app.rest.utils.ContextUtil; import org.dspace.content.Item; import org.dspace.content.MetadataField; import org.dspace.content.MetadataValue; import org.dspace.content.service.ItemService; +import org.dspace.content.service.clarin.ClarinItemService; import org.dspace.core.Context; import org.dspace.discovery.IndexableObject; +import org.dspace.web.ContextUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils; @@ -44,25 +45,19 @@ public class ItemConverter @Autowired private ItemService itemService; + @Autowired + private ClarinItemService clarinItemService; + private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(ItemConverter.class); @Override public ItemRest convert(Item obj, Projection projection) { - List approximatedDates = - itemService.getMetadata(obj, "local", "approximateDate", "issued", Item.ANY, false); - if (CollectionUtils.isNotEmpty(approximatedDates) && - StringUtils.isNotBlank(approximatedDates.get(0).getValue())) { - List issuedDates = - itemService.getMetadata(obj, "dc", "date", "issued", Item.ANY, false); - issuedDates.forEach(metadataValue -> metadataValue.setValue(approximatedDates.get(0).getValue())); - - // Remove the date from the `dc.date.issued` because it was added into `local.approximateDate.issued`. - Context context = ContextUtil.obtainContext(requestService.getCurrentRequest().getHttpServletRequest()); - try { - itemService.clearMetadata(context, obj, "dc", "date", "issued", Item.ANY); - } catch (SQLException e) { - log.error("Cannot remove `dc.date.issued` metadata because: " + e.getMessage()); - } + Context context = ContextUtil.obtainContext(requestService.getCurrentRequest().getHttpServletRequest()); + try { + clarinItemService.updateItemDatesMetadata(context, obj); + } catch (SQLException e) { + log.error("Error updating item dates metadata", e); + throw new RuntimeException(e); } ItemRest item = super.convert(obj, projection); diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java index 249daf994c92..8f139a03f5d2 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java @@ -4698,36 +4698,6 @@ public void findAccessStatusForItemTest() throws Exception { .andExpect(jsonPath("$.status", notNullValue())); } - @Test - public void findItemWithUnknownIssuedDate() throws Exception { - context.turnOffAuthorisationSystem(); - - //** GIVEN ** - //1. A community-collection structure with one parent community and one collection - parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); - Collection col = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection").build(); - - //2. Three public items that are readable by Anonymous with different subjects - Item publicItem = ItemBuilder.createItem(context, col) - .withTitle("Public item") - .withIssueDate("2021-04-27") - .withMetadata("local", "approximateDate", "issued", "unknown") - .withAuthor("Smith, Donald").withAuthor("Doe, John") - .withSubject("ExtraEntry") - .build(); - - context.restoreAuthSystemState(); - Matcher publicItemMatcher = ItemMatcher.matchItemWithTitleAndApproximateDateIssued(publicItem, - "Public item", "unknown"); - - getClient().perform(get("/api/core/items/" + publicItem.getID())) - .andExpect(status().isOk()) - .andExpect(jsonPath("$", HalMatcher.matchNoEmbeds())) - .andExpect(jsonPath("$", publicItemMatcher)); - } - @Test public void submitterShouldSeeLocalNoteMetadata() throws Exception { // Admin - should see `local.submission.note` and `dc.description.provenance` @@ -4837,4 +4807,68 @@ public void searchByHandle() throws Exception { ))); } + /** + * If the local.approximateDate.issued has a value like 'cca 1938 - 1945', then dc.date.issued = 0000. + */ + @Test + public void copyApproximateDateIntoDateIssued_whenApproximateDateHasMultipleValues() throws Exception { + context.turnOffAuthorisationSystem(); + //** GIVEN ** + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + Item publicItem = ItemBuilder.createItem(context, col1) + .withTitle("Item with dates") + .withIssueDate("2017-10-17") + .withMetadata("local", "approximateDate", "issued", "cca 1938 - 1945") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + context.restoreAuthSystemState(); + + String adminToken = getAuthToken(admin.getEmail(), password); + getClient(adminToken).perform(get("/api/core/items/" + publicItem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", HalMatcher.matchNoEmbeds())) + .andExpect(jsonPath("$.metadata", Matchers.allOf( + matchMetadata("dc.date.issued", "0000")))); + } + + /** + * If the local.approximateDate.issued has a value like '1938, 1945, 2022', then dc.date.issued = 2022. + */ + @Test + public void copyApproximateDateIntoDateIssued_whenApproximateDateHasRangeOfValues() throws Exception { + context.turnOffAuthorisationSystem(); + //** GIVEN ** + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + Item publicItem = ItemBuilder.createItem(context, col1) + .withTitle("Item with dates") + .withIssueDate("2017-10-17") + .withMetadata("local", "approximateDate", "issued", "1938, 1945, 2022") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + context.restoreAuthSystemState(); + + String adminToken = getAuthToken(admin.getEmail(), password); + getClient(adminToken).perform(get("/api/core/items/" + publicItem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", HalMatcher.matchNoEmbeds())) + .andExpect(jsonPath("$.metadata", Matchers.allOf( + matchMetadata("dc.date.issued", "2022")))); + } + } From 1f615ff2b679cd41deb4d9d31d504b33a85fc907 Mon Sep 17 00:00:00 2001 From: milanmajchrak Date: Fri, 24 May 2024 13:50:21 +0200 Subject: [PATCH 2/4] Fixed checkstyle issues --- .../java/org/dspace/content/clarin/ClarinItemServiceImpl.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/clarin/ClarinItemServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/clarin/ClarinItemServiceImpl.java index 0d9758f5c101..2329542152b6 100644 --- a/dspace-api/src/main/java/org/dspace/content/clarin/ClarinItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/clarin/ClarinItemServiceImpl.java @@ -31,7 +31,6 @@ import org.dspace.content.service.clarin.ClarinItemService; import org.dspace.core.Constants; import org.dspace.core.Context; -import org.dspace.services.RequestService; import org.springframework.beans.factory.annotation.Autowired; /** @@ -217,7 +216,7 @@ public void updateItemDatesMetadata(Context context, Item item) throws SQLExcept List approximatedDates = itemService.getMetadata(item, "local", "approximateDate", "issued", Item.ANY, false); - if(CollectionUtils.isEmpty(approximatedDates) || StringUtils.isBlank(approximatedDates.get(0).getValue())) { + if (CollectionUtils.isEmpty(approximatedDates) || StringUtils.isBlank(approximatedDates.get(0).getValue())) { log.warn("Cannot update item dates metadata because the approximate date is empty."); return; } From e4e94a7ca4f54c4e515e257a32f9565f9d78c3fe Mon Sep 17 00:00:00 2001 From: milanmajchrak Date: Fri, 24 May 2024 14:49:49 +0200 Subject: [PATCH 3/4] The servlet request could be null. --- .../org/dspace/content/clarin/ClarinItemServiceImpl.java | 5 +++++ .../org/dspace/app/rest/converter/ItemConverter.java | 9 +++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/clarin/ClarinItemServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/clarin/ClarinItemServiceImpl.java index 2329542152b6..50b1ff84dcc8 100644 --- a/dspace-api/src/main/java/org/dspace/content/clarin/ClarinItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/clarin/ClarinItemServiceImpl.java @@ -213,6 +213,11 @@ public void updateItemFilesMetadata(Context context, Bitstream bit) throws SQLEx @Override public void updateItemDatesMetadata(Context context, Item item) throws SQLException { + if (Objects.isNull(context)) { + log.error("Cannot update item dates metadata because the context is null."); + return; + } + List approximatedDates = itemService.getMetadata(item, "local", "approximateDate", "issued", Item.ANY, false); diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ItemConverter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ItemConverter.java index dd71cb3a26d8..9f280e55a6de 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ItemConverter.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ItemConverter.java @@ -19,6 +19,7 @@ import org.dspace.app.rest.model.ItemRest; import org.dspace.app.rest.model.MetadataValueList; import org.dspace.app.rest.projection.Projection; +import org.dspace.app.rest.utils.ContextUtil; import org.dspace.content.Item; import org.dspace.content.MetadataField; import org.dspace.content.MetadataValue; @@ -26,7 +27,7 @@ import org.dspace.content.service.clarin.ClarinItemService; import org.dspace.core.Context; import org.dspace.discovery.IndexableObject; -import org.dspace.web.ContextUtil; +import org.dspace.services.model.Request; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils; @@ -52,7 +53,11 @@ public class ItemConverter @Override public ItemRest convert(Item obj, Projection projection) { - Context context = ContextUtil.obtainContext(requestService.getCurrentRequest().getHttpServletRequest()); + Context context = null; + Request currentRequest = requestService.getCurrentRequest(); + if (currentRequest != null) { + context = ContextUtil.obtainContext(currentRequest.getHttpServletRequest()); + } try { clarinItemService.updateItemDatesMetadata(context, obj); } catch (SQLException e) { From ca8e9fbc5ea1dde160c016a0d771af1a909924e7 Mon Sep 17 00:00:00 2001 From: milanmajchrak Date: Mon, 27 May 2024 08:19:35 +0200 Subject: [PATCH 4/4] Update the comment to make description more clear. --- .../dspace/content/service/clarin/ClarinItemService.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/service/clarin/ClarinItemService.java b/dspace-api/src/main/java/org/dspace/content/service/clarin/ClarinItemService.java index de481db968fd..0559b10e1378 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/clarin/ClarinItemService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/clarin/ClarinItemService.java @@ -92,9 +92,10 @@ public interface ClarinItemService { /** * Update item's metadata about its dates (dc.date.issued, local.approximateDate.issued). - * If the local.approximateDate.issued has a value like 'cca 1938 - 1945' or something else, - * then dc.date.issued = 0000. - * If the local.approximateDate.issued has a value like '1938, 1945, 2022', then dc.date.issued = 2022. + * If the local.approximateDate.issued has any approximate value, e.g. 'cca 1938 - 1945' or 'approx. 1995' + * or similar, use 0000 + * If the local.approximateDate.issued has several values, e.g. 1993, 1918, 2021 use the last one: + * `dc.date.issued` = 2021 * * @param context DSpace context object * @param item Update metadata for this Item