From 1eb79714fdecb6591d96866ea4df60f497125b14 Mon Sep 17 00:00:00 2001 From: milanmajchrak <90026355+milanmajchrak@users.noreply.github.com> Date: Tue, 12 Sep 2023 11:05:06 +0200 Subject: [PATCH] internal/epic-pid-service-never-called (#431) * The item is created with configured prefix. * The Configuration property configMap is not shared. The right prefix is added during creating the handle. * The handle is correctly composed and the tests are created * epic changed to local because the local handle should be used by default. * Refactoring * Refactoring * Fixed one failing test * Commented out unwanted community configuration. * Fixed failing tests. Instead of changing owningCollection I used Context events. * Fixed checkstyle * Fixed failing IT. It was needed to update configuraition property. * Fixed failing integration tests - the community configuration service wasn't restored. --- .../content/InstallItemServiceImpl.java | 9 ++ .../content/clarin/ClarinItemServiceImpl.java | 87 ++++++++++++++++++ .../service/clarin/ClarinItemService.java | 19 ++++ .../ClarinSolrItemsCommunityIndexPlugin.java | 40 ++------ .../org/dspace/handle/HandleServiceImpl.java | 66 ++++++++++++-- .../handle/PIDCommunityConfiguration.java | 21 +++++ .../org/dspace/handle/PIDConfiguration.java | 91 +++++++++++-------- .../test/data/dspaceFolder/config/local.cfg | 4 + .../dspace/handle/PIDConfigurationTest.java | 46 +++++++++- .../handle/dao/impl/HandleDAOImplTest.java | 5 +- .../ClarinWorkspaceItemRestRepositoryIT.java | 79 ++++++++++++++++ .../app/rest/HandleRestRepositoryIT.java | 43 +++++++++ dspace/config/clarin-dspace.cfg | 6 +- 13 files changed, 437 insertions(+), 79 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/InstallItemServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/InstallItemServiceImpl.java index 0a824c98e086..dff1790c7657 100644 --- a/dspace-api/src/main/java/org/dspace/content/InstallItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/InstallItemServiceImpl.java @@ -42,6 +42,8 @@ */ public class InstallItemServiceImpl implements InstallItemService { + public static final String SET_OWNING_COLLECTION_EVENT_DETAIL = "setCollection:"; + @Autowired(required = true) protected ContentServiceFactory contentServiceFactory; @Autowired(required = true) @@ -73,6 +75,13 @@ public Item installItem(Context c, InProgressSubmission is, AuthorizeException { Item item = is.getItem(); Collection collection = is.getCollection(); + + // CLARIN + // The owning collection is needed for getting owning community and creating configured handle. + c.addEvent(new Event(Event.MODIFY, Constants.ITEM, item.getID(), + SET_OWNING_COLLECTION_EVENT_DETAIL + collection.getID())); + // CLARIN + // Get map of filters to use for identifier types. Map, Filter> filters = FilterUtils.getIdentifierFilters(false); try { 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 c0be6ad538cc..936d1e136545 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 @@ -9,11 +9,19 @@ import java.sql.SQLException; import java.util.List; +import java.util.Objects; import java.util.UUID; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.logging.log4j.Logger; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.DSpaceObject; import org.dspace.content.Item; import org.dspace.content.dao.clarin.ClarinItemDAO; +import org.dspace.content.service.CollectionService; import org.dspace.content.service.clarin.ClarinItemService; +import org.dspace.core.Constants; import org.dspace.core.Context; import org.springframework.beans.factory.annotation.Autowired; @@ -25,11 +33,90 @@ */ public class ClarinItemServiceImpl implements ClarinItemService { + private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(ClarinItemServiceImpl.class); @Autowired ClarinItemDAO clarinItemDAO; + @Autowired + CollectionService collectionService; + @Override public List findByBitstreamUUID(Context context, UUID bitstreamUUID) throws SQLException { return clarinItemDAO.findByBitstreamUUID(context, bitstreamUUID); } + + @Override + public Community getOwningCommunity(Context context, DSpaceObject dso) { + if (Objects.isNull(dso)) { + return null; + } + int type = dso.getType(); + if (Objects.equals(type, Constants.COMMUNITY)) { + return (Community) dso; + } + + Collection owningCollection = null; + if (Objects.equals(type, Constants.COLLECTION)) { + owningCollection = (Collection) dso; + } + + if (Objects.equals(type, Constants.ITEM)) { + owningCollection = ((Item) dso).getOwningCollection(); + } + + if (Objects.isNull(owningCollection)) { + return null; + } + + try { + List communities = owningCollection.getCommunities(); + if (CollectionUtils.isEmpty(communities)) { + log.error("Community list of the owning collection is empty."); + return null; + } + + // First community is the owning community. + Community owningCommunity = communities.get(0); + if (Objects.isNull(owningCommunity)) { + log.error("Owning community is null."); + return null; + } + + return owningCommunity; + } catch (SQLException e) { + log.error("Cannot getOwningCommunity for the Item: " + dso.getID() + ", because: " + e.getSQLState()); + } + + return null; + } + + @Override + public Community getOwningCommunity(Context context, UUID owningCollectionId) throws SQLException { + Collection owningCollection = collectionService.find(context, owningCollectionId); + + if (Objects.isNull(owningCollection)) { + return null; + } + + try { + List communities = owningCollection.getCommunities(); + if (CollectionUtils.isEmpty(communities)) { + log.error("Community list of the owning collection is empty."); + return null; + } + + // First community is the owning community. + Community owningCommunity = communities.get(0); + if (Objects.isNull(owningCommunity)) { + log.error("Owning community is null."); + return null; + } + + return owningCommunity; + } catch (SQLException e) { + log.error("Cannot getOwningCommunity for the Collection: " + owningCollectionId + + ", because: " + e.getSQLState()); + } + return null; + } } 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 6382139c736e..029b251571d3 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 @@ -11,6 +11,8 @@ import java.util.List; import java.util.UUID; +import org.dspace.content.Community; +import org.dspace.content.DSpaceObject; import org.dspace.content.Item; import org.dspace.core.Context; @@ -30,4 +32,21 @@ public interface ClarinItemService { * @throws SQLException database error */ List findByBitstreamUUID(Context context, UUID bitstreamUUID) throws SQLException; + + /** + * Get item/collection/community's owning community + * @param context DSpace context object + * @param dso item/collection/community + * @return owning community or null + */ + Community getOwningCommunity(Context context, DSpaceObject dso); + + /** + * Get owning community from the collection with UUID which is passed to the method. + * @param context DSpace context object + * @param owningCollectionId UUID of the collection to get the owning community + * @return owning community or null + * @throws SQLException + */ + Community getOwningCommunity(Context context, UUID owningCollectionId) throws SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/discovery/ClarinSolrItemsCommunityIndexPlugin.java b/dspace-api/src/main/java/org/dspace/discovery/ClarinSolrItemsCommunityIndexPlugin.java index 9b64970872e6..fe419cb6d2ff 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/ClarinSolrItemsCommunityIndexPlugin.java +++ b/dspace-api/src/main/java/org/dspace/discovery/ClarinSolrItemsCommunityIndexPlugin.java @@ -7,18 +7,16 @@ */ package org.dspace.discovery; -import java.sql.SQLException; -import java.util.List; import java.util.Objects; -import org.apache.commons.collections4.CollectionUtils; import org.apache.logging.log4j.Logger; import org.apache.solr.common.SolrInputDocument; -import org.dspace.content.Collection; import org.dspace.content.Community; import org.dspace.content.Item; +import org.dspace.content.service.clarin.ClarinItemService; import org.dspace.core.Context; import org.dspace.discovery.indexobject.IndexableItem; +import org.springframework.beans.factory.annotation.Autowired; /** * Plugin for indexing the Items community. It helps search the Item by the community. @@ -30,40 +28,18 @@ public class ClarinSolrItemsCommunityIndexPlugin implements SolrServiceIndexPlug private static final Logger log = org.apache.logging.log4j.LogManager .getLogger(ClarinSolrItemsCommunityIndexPlugin.class); + @Autowired(required = true) + protected ClarinItemService clarinItemService; + @Override public void additionalIndex(Context context, IndexableObject indexableObject, SolrInputDocument document) { if (indexableObject instanceof IndexableItem) { Item item = ((IndexableItem) indexableObject).getIndexedObject(); - String owningCommunity = this.getOwningCommunity(context, item); - document.addField("items_owning_community", owningCommunity); - } - } + Community owningCommunity = clarinItemService.getOwningCommunity(context, item); + String communityName = Objects.isNull(owningCommunity) ? " " : owningCommunity.getName(); - private String getOwningCommunity(Context context, Item item) { - if (Objects.isNull(item)) { - return " "; + document.addField("items_owning_community", communityName); } - Collection owningCollection = item.getOwningCollection(); - try { - List communities = owningCollection.getCommunities(); - if (CollectionUtils.isEmpty(communities)) { - log.error("Community list of the owning collection is empty."); - return " "; - } - - // First community is the owning community. - Community owningCommunity = communities.get(0); - if (Objects.isNull(owningCommunity)) { - log.error("Owning community is null."); - return " "; - } - - return owningCommunity.getName(); - } catch (SQLException e) { - log.error("Cannot getOwningCommunity for the Item: " + item.getID() + ", because: " + e.getSQLState()); - } - - return " "; } } diff --git a/dspace-api/src/main/java/org/dspace/handle/HandleServiceImpl.java b/dspace-api/src/main/java/org/dspace/handle/HandleServiceImpl.java index 616bb72e18c6..24166d42f3db 100644 --- a/dspace-api/src/main/java/org/dspace/handle/HandleServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/handle/HandleServiceImpl.java @@ -7,12 +7,16 @@ */ package org.dspace.handle; +import static org.dspace.content.InstallItemServiceImpl.SET_OWNING_COLLECTION_EVENT_DETAIL; + import java.io.IOException; import java.sql.SQLException; import java.util.ArrayList; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.Objects; +import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -21,11 +25,14 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.dspace.api.DSpaceApi; +import org.dspace.content.Community; import org.dspace.content.DSpaceObject; import org.dspace.content.Item; import org.dspace.content.service.SiteService; +import org.dspace.content.service.clarin.ClarinItemService; import org.dspace.core.Constants; import org.dspace.core.Context; +import org.dspace.event.Event; import org.dspace.handle.dao.HandleDAO; import org.dspace.handle.service.HandleService; import org.dspace.services.ConfigurationService; @@ -62,6 +69,8 @@ public class HandleServiceImpl implements HandleService { @Autowired protected SiteService siteService; + @Autowired + protected ClarinItemService clarinItemService; private static final Pattern[] IDENTIFIER_PATTERNS = { Pattern.compile("^hdl:(.*)$"), @@ -143,8 +152,8 @@ public String getCanonicalForm(String handle) { public String createHandle(Context context, DSpaceObject dso) throws SQLException { Handle handle = handleDAO.create(context, new Handle()); -// String handleId = createId(context, dso); - String handleId = createId(context); + String handleId = createId(context, dso); +// String handleId = createId(context); handle.setHandle(handleId); handle.setDSpaceObject(dso); dso.addHandle(handle); @@ -387,10 +396,12 @@ protected String createId(Context context, DSpaceObject dso) throws SQLException //create handle for another type of dspace objects return createdId; } + Community owningCommunity = getOwningCommunity(context, dso); + UUID owningCommunityId = Objects.isNull(owningCommunity) ? null : owningCommunity.getID(); - //add subprefix for item handle + // add subprefix for item handle PIDCommunityConfiguration pidCommunityConfiguration = PIDConfiguration - .getPIDCommunityConfiguration(dso.getID()); + .getPIDCommunityConfiguration(owningCommunityId); //Which type is pis community configuration? if (pidCommunityConfiguration.isEpic()) { String handleId; @@ -413,10 +424,11 @@ protected String createId(Context context, DSpaceObject dso) throws SQLException } return handleId; } else if (pidCommunityConfiguration.isLocal()) { + String prefix = pidCommunityConfiguration.getPrefix(); String handleSubprefix = pidCommunityConfiguration.getSubprefix(); if (Objects.nonNull(handleSubprefix) && !handleSubprefix.isEmpty()) { - //create local handle - return handlePrefix + (handlePrefix.endsWith("/") ? "" : "/") + // create local handle + return prefix + (handlePrefix.endsWith("/") ? "" : "/") + handleSubprefix + "-" + handleSuffix.toString(); } } else { @@ -468,6 +480,48 @@ public String parseHandle(String identifier) { return null; } + /** + * + * @param context DSpace context + * @param dso DSpaceObject + * @return dso owning community + * @throws SQLException + */ + private Community getOwningCommunity(Context context, DSpaceObject dso) throws SQLException { + // There is stored event with dso collection UUID in the context + Event setOwningCollectionEvent = getClarinSetOwningCollectionEvent(context); + + String detail = Objects.isNull(setOwningCollectionEvent) ? "" : setOwningCollectionEvent.getDetail(); + if (StringUtils.isNotBlank(detail)) { + int searchingCharIndex = detail.indexOf(":"); + detail = detail.substring(searchingCharIndex + 1); + return clarinItemService.getOwningCommunity(context, UUID.fromString(detail)); + } + + return clarinItemService.getOwningCommunity(context, dso); + } + + /** + * Context has a lot of events stored in the list. Fetch just that one with the special detail prefix. + * @param context DSpace context + * @return event with owningCollection UUID + */ + private Event getClarinSetOwningCollectionEvent(Context context) { + int index = -1; + LinkedList allEvents = context.getEvents(); + for (Event event: allEvents) { + index++; + if (StringUtils.isBlank(event.getDetail())) { + continue; + } + if (StringUtils.startsWith(event.getDetail(), SET_OWNING_COLLECTION_EVENT_DETAIL)) { + context.getEvents().remove(index); + return event; + } + } + return null; + } + @Override public String[] getAdditionalPrefixes() { return configurationService.getArrayProperty("handle.additional.prefixes"); diff --git a/dspace-api/src/main/java/org/dspace/handle/PIDCommunityConfiguration.java b/dspace-api/src/main/java/org/dspace/handle/PIDCommunityConfiguration.java index 0901248c3840..bb4f9b41ffac 100644 --- a/dspace-api/src/main/java/org/dspace/handle/PIDCommunityConfiguration.java +++ b/dspace-api/src/main/java/org/dspace/handle/PIDCommunityConfiguration.java @@ -7,6 +7,7 @@ */ package org.dspace.handle; +import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.UUID; @@ -18,6 +19,7 @@ * Class encapsulating community based PIDs configuration. * * @author Michaela Paurikova (michaela.paurikova at dataquest.sk) + * @author Milan Majchrak (milan.majchrak at dataquest.sk) */ public class PIDCommunityConfiguration { @@ -119,4 +121,23 @@ public UUID getCommunityID() { } return communityID; } + + /** + * Creates new AssignmentRules from given string + * + * @param s String with assignment rules + * @return New instance of this class + */ + public static PIDCommunityConfiguration fromString(String s) { + Map configMap = new HashMap(); + for (String part : s.split(",")) { + String[] keyValue = part.split("=", 2); + if (keyValue.length == 2) { + String key = keyValue[0].trim(); + String value = keyValue[1].trim(); + configMap.put(key, value); + } + } + return new PIDCommunityConfiguration(configMap); + } } diff --git a/dspace-api/src/main/java/org/dspace/handle/PIDConfiguration.java b/dspace-api/src/main/java/org/dspace/handle/PIDConfiguration.java index ccceea39f3f6..8bb8e9a178f9 100644 --- a/dspace-api/src/main/java/org/dspace/handle/PIDConfiguration.java +++ b/dspace-api/src/main/java/org/dspace/handle/PIDConfiguration.java @@ -8,6 +8,8 @@ package org.dspace.handle; import java.sql.SQLException; +import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -17,6 +19,7 @@ import java.util.UUID; import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.Logger; import org.dspace.content.Community; import org.dspace.content.DSpaceObject; @@ -32,6 +35,7 @@ * Class encapsulating PIDs configuration. * * @author Michaela Paurikova (michaela.paurikova at dataquest.sk) + * @author Milan Majchrak (milan.majchrak at dataquest.sk) */ @Component public class PIDConfiguration { @@ -58,8 +62,8 @@ private PIDConfiguration() { * Initializes the singleton */ private void initialize() { - //All configurations are loaded into one array. - //New configuration starts after loaded part contains "community". + // All configurations are loaded into one array. + // New configuration starts after loaded part contains "community". String[] pidCommunityConfigurationsArray = configurationService.getArrayProperty (CLARIN_PID_COMMUNITY_CONFIGURATIONS_KEYWORD); @@ -67,42 +71,20 @@ private void initialize() { return; } - //hashmap for creating PIDCommunityConfiguration - Map map = new HashMap(); - pidCommunityConfigurations = new HashMap(); - //exists minimally one configuration, so first community is added to map not in cycle - String[] keyValue = pidCommunityConfigurationsArray[0].split("="); - - if (keyValue.length < 2) { - throw new RuntimeException("Cannot initialize PIDConfiguration, because the configuration " + - "property has wrong syntax. Property must be in the format: `key=value`"); + String convertedProperties = convertPropertyToValidString(pidCommunityConfigurationsArray); + if (StringUtils.isEmpty(convertedProperties)) { + log.error("Cannot convert community array property into valid string."); + return; } - String key = keyValue[0].trim(); - String value = keyValue[1].trim(); - map.put(key, value); - //another parts of configurations - //start from the first position because the zero position was already added - for (int i = 1; i < pidCommunityConfigurationsArray.length; i++) { - keyValue = pidCommunityConfigurationsArray[i].split("="); - key = keyValue[0].trim(); - value = keyValue[1].trim(); - //finding the end of the configuration - if (key.equals("community")) { - //creating PIDCOmmunityConfiguration - PIDCommunityConfiguration pidCommunityConfiguration = new PIDCommunityConfiguration (map); - pidCommunityConfigurations.put( - pidCommunityConfiguration.getCommunityID(), - pidCommunityConfiguration); - //cleaning map for other configuration - map.clear(); - } - map.put(key, value); + + pidCommunityConfigurations = new HashMap(); + for (String pidCommunityConfigurationString : convertedProperties.split(";")) { + PIDCommunityConfiguration pidCommunityConfiguration = PIDCommunityConfiguration + .fromString(pidCommunityConfigurationString); + pidCommunityConfigurations.put( + pidCommunityConfiguration.getCommunityID(), + pidCommunityConfiguration); } - //creating PIDCommunityConfiguration because the last configuration found has not been added - PIDCommunityConfiguration pidCommunityConfiguration = new PIDCommunityConfiguration (map); - pidCommunityConfigurations.put( - pidCommunityConfiguration.getCommunityID(), - pidCommunityConfiguration); } /** @@ -232,4 +214,41 @@ public Set getSupportedPrefixes() { } return prefixes; } + + /** + * Convert array property into single string property divided by `;` and not by `,`. + * @param pidCommunityConfigurationsArray + * @return + */ + public String convertPropertyToValidString(String[] pidCommunityConfigurationsArray) { + String wholePccString = String.join(",", pidCommunityConfigurationsArray); + String[] splittedByCommunity = wholePccString.split("community="); + Collection pccWithoutCommunity = Arrays.asList(splittedByCommunity); + + // pcc = pidCommunityConfigurations + StringBuilder convertedPccString = new StringBuilder(); + // Add `community=` string into start of the property + for (String pcc : pccWithoutCommunity) { + if (StringUtils.isEmpty(pcc)) { + continue; + } + pcc = "community=" + pcc; + // If last character is `,` replace it with `;` + if (pcc.endsWith(",")) { + int indexToReplace = pcc.lastIndexOf(","); + pcc = pcc.substring(0, indexToReplace) + ";"; + } + convertedPccString.append(pcc); + } + return convertedPccString.toString(); + } + + /** + * Reload community configuration. It is for testing purposes. + */ + public void reloadPidCommunityConfigurations() { + pidCommunityConfigurations.clear(); + pidCommunityConfigurations = null; + initialize(); + } } diff --git a/dspace-api/src/test/data/dspaceFolder/config/local.cfg b/dspace-api/src/test/data/dspaceFolder/config/local.cfg index fdbb50b62dbd..f3f01989a43b 100644 --- a/dspace-api/src/test/data/dspaceFolder/config/local.cfg +++ b/dspace-api/src/test/data/dspaceFolder/config/local.cfg @@ -264,3 +264,7 @@ webui.browse.link.2 = subject:dc.subject.* # If the versioning is disabled Versioning Integration Tests will fail - allow it for the tests versioning.enabled=true + +### PID config +lr.pid.community.configurations = community=47501cdc-e2eb-44e5-85e0-89a31dc8ceee, prefix=123456789, type=epic, canonical_prefix=http://hdl.handle.net/, subprefix=1 +lr.pid.community.configurations = community=*, prefix=123456789, type=local, canonical_prefix=http://hdl.handle.net/, subprefix=2 diff --git a/dspace-api/src/test/java/org/dspace/handle/PIDConfigurationTest.java b/dspace-api/src/test/java/org/dspace/handle/PIDConfigurationTest.java index 39bec0386f09..9cc6148f3bbc 100644 --- a/dspace-api/src/test/java/org/dspace/handle/PIDConfigurationTest.java +++ b/dspace-api/src/test/java/org/dspace/handle/PIDConfigurationTest.java @@ -10,7 +10,10 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; +import java.lang.reflect.Field; import java.sql.SQLException; +import java.util.Map; +import java.util.UUID; import org.dspace.AbstractUnitTest; import org.dspace.authorize.AuthorizeException; @@ -27,10 +30,13 @@ import org.junit.Ignore; import org.junit.Test; +/* Created for LINDAT/CLARIAH-CZ (UFAL) */ /** * Tests for PID configuration. * * @author Michaela Paurikova (michaela.paurikova at dataquest.sk) + * @author Milan Majchrak (milan.majchrak at dataquest.sk) + * @author Milan Majchrak (milan.majchrak at dataquest.sk) */ public class PIDConfigurationTest extends AbstractUnitTest { private static final String AUTHOR = "Test author name"; @@ -75,10 +81,48 @@ public void testItemHandle() { assertEquals("123456789/1-" + customSuffix[1], handle); } - @Test public void testCollectionHandle() { String handle = col.getHandle(); assertEquals("123456789/" + (handle.split("/"))[1], handle); } +// +// /* +// This is the config from test local.cfg: +// lr.pid.community.configurations = community=47501cdc-e2eb-44e5-85e0-89a31dc8ceee, prefix=123456789, type=epic, canonical_prefix=http://hdl.handle.net/, subprefix=1 +// lr.pid.community.configurations = community=09f09b11-cba1-4c43-9e01-29fe919991ab, prefix=123456789, type=epic, canonical_prefix=http://hdl.handle.net/, subprefix=2 +// lr.pid.community.configurations = community=*, prefix=123456789, type=epic, canonical_prefix=http://hdl.handle.net/, subprefix=2 +//*/ + @Test + public void testInitMultipleCommunityConfigs() { + PIDConfiguration pidConfiguration = PIDConfiguration.getInstance(); + // now check that we have 2 community configurations in the test local.cfg + assertEquals(2, pidConfiguration.getPIDCommunityConfigurations().size()); + } +// + @Test + public void testInitCommunityConfigSubprefix() { + PIDConfiguration pidConfiguration = PIDConfiguration.getInstance(); + // get the first one and check the subprefix is 1 + PIDCommunityConfiguration pidCommunityConfiguration = pidConfiguration.getPIDCommunityConfiguration( + UUID.fromString("47501cdc-e2eb-44e5-85e0-89a31dc8ceee")); + assertEquals("Subprefix should be 1", "1", pidCommunityConfiguration.getSubprefix()); + } + + @Test + public void testInitCommunityConfigMapShouldNotBeShared() throws NoSuchFieldException, IllegalAccessException { + PIDConfiguration pidConfiguration = PIDConfiguration.getInstance(); + PIDCommunityConfiguration pidCommunityConfiguration1 = + pidConfiguration.getPIDCommunityConfiguration( + UUID.fromString("47501cdc-e2eb-44e5-85e0-89a31dc8ceee")); + PIDCommunityConfiguration pidCommunityConfiguration2 = + pidConfiguration.getPIDCommunityConfiguration(null); + assertEquals("Com2 should have local type", "local", pidCommunityConfiguration2.getType()); + // get the private PIDCommunityConfiguration.configMap via reflection + Field field = PIDCommunityConfiguration.class.getDeclaredField("configMap"); + field.setAccessible(true); + Map configMap = (Map) field.get(pidCommunityConfiguration1); + configMap.put("type", "epic"); + assertEquals("Com2 should still have local type", "local", pidCommunityConfiguration2.getType()); + } } diff --git a/dspace-api/src/test/java/org/dspace/handle/dao/impl/HandleDAOImplTest.java b/dspace-api/src/test/java/org/dspace/handle/dao/impl/HandleDAOImplTest.java index 130f5f91b5a2..bcab18cb8a30 100644 --- a/dspace-api/src/test/java/org/dspace/handle/dao/impl/HandleDAOImplTest.java +++ b/dspace-api/src/test/java/org/dspace/handle/dao/impl/HandleDAOImplTest.java @@ -76,6 +76,8 @@ public class HandleDAOImplTest extends AbstractUnitTest { private static final String SUFFIX_3 = "303"; private static final String SUFFIX_4 = "404"; + private static final String SUBPREFIX = "2"; + @Before @Override public void init() { @@ -147,7 +149,8 @@ public void updateHandlesWithNewPrefix() throws Exception { context.commit(); assertEquals(newPrefix + "/" + SUFFIX_1, itemService.find(context, item1.getID()).getHandle()); - assertEquals(newPrefix + "/" + SUFFIX_2, itemService.find(context, item2.getID()).getHandle()); + assertEquals(newPrefix + "/" + SUBPREFIX + "-" + SUFFIX_2, + itemService.find(context, item2.getID()).getHandle()); assertEquals(newPrefix + "/" + SUFFIX_3, itemService.find(context, item3.getID()).getHandle()); //Ensure that records not matching the old prefix are not touched diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ClarinWorkspaceItemRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ClarinWorkspaceItemRestRepositoryIT.java index 4b46b81cba3b..2e3ad348e3df 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ClarinWorkspaceItemRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ClarinWorkspaceItemRestRepositoryIT.java @@ -41,12 +41,15 @@ import org.dspace.builder.WorkspaceItemBuilder; import org.dspace.content.Collection; import org.dspace.content.Community; +import org.dspace.content.Item; import org.dspace.content.WorkspaceItem; import org.dspace.content.clarin.ClarinLicense; import org.dspace.content.clarin.ClarinLicenseLabel; +import org.dspace.content.service.InstallItemService; import org.dspace.content.service.clarin.ClarinLicenseLabelService; import org.dspace.content.service.clarin.ClarinLicenseResourceMappingService; import org.dspace.content.service.clarin.ClarinLicenseService; +import org.dspace.handle.PIDConfiguration; import org.dspace.services.ConfigurationService; import org.junit.Assert; import org.junit.Test; @@ -73,6 +76,8 @@ public class ClarinWorkspaceItemRestRepositoryIT extends AbstractControllerInteg private ClarinLicenseLabelService clarinLicenseLabelService; @Autowired private ClarinLicenseResourceMappingService clarinLicenseResourceMappingService; + @Autowired + private InstallItemService installItemService; @Test public void uploadFileBiggerThanUploadFileSizeLimit() throws Exception { @@ -810,6 +815,80 @@ public void updateClarinLicenseInWI() throws Exception { .andExpect(jsonPath("$.bitstreams", is(1))); } + /** + * Create Item with standard handle. The handle definition for every community is configured + * by the `lr.pid.community.configurations` properties. + */ + @Test + public void createItemWithConfiguredNormalHandle() throws Exception { + context.turnOffAuthorisationSystem(); + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Collection col = CollectionBuilder.createCollection(context, parentCommunity) + .withName("Collection").build(); + WorkspaceItem wItem = WorkspaceItemBuilder.createWorkspaceItem(context, col) + .withTitle("Item with custom handle") + .withIssueDate("2017-10-17") + .build(); + + Item installedItem = installItemService.installItem(context, wItem); + context.restoreAuthSystemState(); + + Assert.assertNotNull(installedItem); + Assert.assertTrue(installedItem.getHandle().startsWith("123456789/2")); + } + + /** + * Create Item with specific handle. The handle definition for special community is configured + * by the `lr.pid.community.configurations` properties. + */ + @Test + public void createItemWithConfiguredSpecificHandle() throws Exception { + context.turnOffAuthorisationSystem(); + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + + // Set property in the cfg + String specificCommunityHandleDef = "community=" + parentCommunity.getID() + ",prefix=LRT," + + "type=local,canonical_prefix=http://hdl.handle.net/,subprefix=100"; + configurationService.setProperty("lr.pid.community.configurations", specificCommunityHandleDef); + + // Reload the set property in the hash map. + PIDConfiguration pidConfiguration = PIDConfiguration.getInstance(); + pidConfiguration.reloadPidCommunityConfigurations(); + + Collection col = CollectionBuilder.createCollection(context, parentCommunity) + .withName("Collection").build(); + WorkspaceItem wItem = WorkspaceItemBuilder.createWorkspaceItem(context, col) + .withTitle("Item with custom handle") + .withIssueDate("2017-10-17") + .build(); + + Item installedItem = installItemService.installItem(context, wItem); + context.restoreAuthSystemState(); + + Assert.assertNotNull(installedItem); + Assert.assertTrue(installedItem.getHandle().startsWith("LRT/100")); + + // Restore community configuration + context.turnOffAuthorisationSystem(); + // Set property in the cfg + String restoreAllCommunityHandleDef = "community=*, prefix=123456789, " + + "type=local, canonical_prefix=http://hdl.handle.net/, subprefix=2"; + String restoreSpecificCommunityHandleDef = "community=09f09b11-cba1-4c43-9e01-29fe919991ab, " + + "prefix=123456789, " + "type=local, canonical_prefix=http://hdl.handle.net/, subprefix=2"; + ArrayList configArrayCommunityConfig = new ArrayList<>(2); + configArrayCommunityConfig.add(restoreAllCommunityHandleDef); + configArrayCommunityConfig.add(restoreSpecificCommunityHandleDef); + configurationService.setProperty("lr.pid.community.configurations", configArrayCommunityConfig); + + // Reload the set property in the hash map. + pidConfiguration.reloadPidCommunityConfigurations(); + context.restoreAuthSystemState(); + } + /** * Create Clarin License Label object for testing purposes. */ diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/HandleRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/HandleRestRepositoryIT.java index 234419552a78..1240459d1e68 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/HandleRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/HandleRestRepositoryIT.java @@ -45,8 +45,10 @@ import org.dspace.content.service.CollectionService; import org.dspace.content.service.ItemService; import org.dspace.handle.Handle; +import org.dspace.handle.PIDConfiguration; import org.dspace.handle.service.HandleClarinService; import org.dspace.handle.service.HandleService; +import org.dspace.services.ConfigurationService; import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Test; @@ -80,6 +82,9 @@ public class HandleRestRepositoryIT extends AbstractControllerIntegrationTest { @Autowired private HandleService handleService; + + @Autowired + private ConfigurationService configurationService; @Before public void setup() { context.turnOffAuthorisationSystem(); @@ -492,6 +497,16 @@ public void patchSetPrefixWithoutArchive() throws Exception { context.turnOffAuthorisationSystem(); Community community = CommunityBuilder.createCommunity(context).build(); Collection col2 = CollectionBuilder.createCollection(context, community).build(); + + // Set property in the cfg + String specificCommunityHandleDef = "community=" + community.getID() + ",prefix=987654321," + + "type=local,canonical_prefix=http://hdl.handle.net/"; + configurationService.setProperty("lr.pid.community.configurations", specificCommunityHandleDef); + + // Reload the set property in the hash map. + PIDConfiguration pidConfiguration = PIDConfiguration.getInstance(); + pidConfiguration.reloadPidCommunityConfigurations(); + Item newItem = ItemBuilder.createItem(context, col2) .withAuthor(AUTHOR) .build(); @@ -500,6 +515,7 @@ public void patchSetPrefixWithoutArchive() throws Exception { assertEquals(newItem.getHandle().split("/")[0], "987654321"); this.cleanHandles(); + this.restoreCommunityConfiguration(); } @Test @@ -558,6 +574,14 @@ public void patchSetPrefixWithArchive() throws Exception { context.turnOffAuthorisationSystem(); Community community = CommunityBuilder.createCommunity(context).build(); Collection col2 = CollectionBuilder.createCollection(context, community).build(); + // Set property in the cfg + String specificCommunityHandleDef = "community=" + community.getID() + ",prefix=987654321," + + "type=local,canonical_prefix=http://hdl.handle.net/"; + configurationService.setProperty("lr.pid.community.configurations", specificCommunityHandleDef); + + // Reload the set property in the hash map. + PIDConfiguration pidConfiguration = PIDConfiguration.getInstance(); + pidConfiguration.reloadPidCommunityConfigurations(); Item newItem = ItemBuilder.createItem(context, col2) .withAuthor(AUTHOR) .build(); @@ -582,6 +606,7 @@ public void patchSetPrefixWithArchive() throws Exception { assertEquals(archivedExternalHandle2.getUrl(), externalHandle2.getUrl()); this.cleanHandles(); + this.restoreCommunityConfiguration(); } // Clean handles of all created handles (items, cmmunity, collection, archived handles, external handles...) @@ -617,4 +642,22 @@ private Handle createExternalHandle(String strHandle) throws Exception { Handle handle = handleClarinService.findByID(context, handleId); return handle; } + + private void restoreCommunityConfiguration() { + context.turnOffAuthorisationSystem(); + // Set property in the cfg + String allCommunityHandleDef = "community=*, prefix=123456789, " + + "type=local, canonical_prefix=http://hdl.handle.net/, subprefix=2"; + String specificCommunityHandleDef = "community=09f09b11-cba1-4c43-9e01-29fe919991ab, prefix=123456789, " + + "type=local, canonical_prefix=http://hdl.handle.net/, subprefix=2"; + ArrayList configArrayCommunityConfig = new ArrayList<>(2); + configArrayCommunityConfig.add(allCommunityHandleDef); + configArrayCommunityConfig.add(specificCommunityHandleDef); + configurationService.setProperty("lr.pid.community.configurations", configArrayCommunityConfig); + + // Reload the set property in the hash map. + PIDConfiguration pidConfiguration = PIDConfiguration.getInstance(); + pidConfiguration.reloadPidCommunityConfigurations(); + context.restoreAuthSystemState(); + } } diff --git a/dspace/config/clarin-dspace.cfg b/dspace/config/clarin-dspace.cfg index b5b19b79a770..0562d134d3a3 100644 --- a/dspace/config/clarin-dspace.cfg +++ b/dspace/config/clarin-dspace.cfg @@ -31,9 +31,9 @@ lr.pid.service.pass = # multiple configurations can be added using a new configuration line # default configuration should have asterisk as the community ID # subprefix is only used for local handles -lr.pid.community.configurations = community=47501cdc-e2eb-44e5-85e0-89a31dc8ceee, prefix=123456789, type=epic, canonical_prefix=http://hdl.handle.net/, subprefix=1 -lr.pid.community.configurations = community=09f09b11-cba1-4c43-9e01-29fe919991ab, prefix=123456789, type=epic, canonical_prefix=http://hdl.handle.net/, subprefix=2 -lr.pid.community.configurations = community=*, prefix=123456789, type=epic, canonical_prefix=http://hdl.handle.net/, subprefix=2 +lr.pid.community.configurations = community=47501cdc-e2eb-44e5-85e0-89a31dc8ceee, prefix=123456789, type=local, canonical_prefix=http://hdl.handle.net/, subprefix=1 +lr.pid.community.configurations = community=09f09b11-cba1-4c43-9e01-29fe919991ab, prefix=123456789, type=local, canonical_prefix=http://hdl.handle.net/, subprefix=2 +lr.pid.community.configurations = community=*, prefix=123456789, type=local, canonical_prefix=http://hdl.handle.net/, subprefix=2 # if true, PID metadata will be filled with object metadata like title lr.pid.resolvemetadata = true