From 2dd957529324aba4db67e7b514ec073a220ff466 Mon Sep 17 00:00:00 2001 From: mohamed eskander Date: Wed, 22 Nov 2023 15:44:22 +0200 Subject: [PATCH 1/5] [CST-12752] handled automatic pattern/services in the LDNConsumer --- .../dspace/app/ldn/LDNMessageConsumer.java | 52 +++++++++---- .../dao/NotifyServiceInboundPatternDao.java | 9 +++ .../NotifyServiceInboundPatternDaoImpl.java | 14 ++++ .../NotifyServiceInboundPatternService.java | 10 +++ ...otifyServiceInboundPatternServiceImpl.java | 6 ++ .../dspace/app/ldn/LDNMessageConsumerIT.java | 78 +++++++++++++++++++ 6 files changed, 154 insertions(+), 15 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/app/ldn/LDNMessageConsumer.java b/dspace-api/src/main/java/org/dspace/app/ldn/LDNMessageConsumer.java index 72ecefb5c8..60420e91f3 100644 --- a/dspace-api/src/main/java/org/dspace/app/ldn/LDNMessageConsumer.java +++ b/dspace-api/src/main/java/org/dspace/app/ldn/LDNMessageConsumer.java @@ -29,12 +29,14 @@ import org.dspace.app.ldn.factory.NotifyServiceFactory; import org.dspace.app.ldn.model.Notification; import org.dspace.app.ldn.service.LDNMessageService; import org.dspace.app.ldn.service.NotifyPatternToTriggerService; +import org.dspace.app.ldn.service.NotifyServiceInboundPatternService; import org.dspace.content.Bitstream; import org.dspace.content.BitstreamFormat; import org.dspace.content.Bundle; import org.dspace.content.Item; import org.dspace.content.MetadataValue; import org.dspace.content.factory.ContentServiceFactory; +import org.dspace.content.logic.LogicalStatement; import org.dspace.content.service.BitstreamService; import org.dspace.content.service.ItemService; import org.dspace.core.Constants; @@ -45,6 +47,7 @@ import org.dspace.event.Consumer; import org.dspace.event.Event; import org.dspace.services.ConfigurationService; import org.dspace.services.factory.DSpaceServicesFactory; +import org.dspace.utils.DSpace; import org.dspace.web.ContextUtil; /** @@ -55,6 +58,7 @@ import org.dspace.web.ContextUtil; public class LDNMessageConsumer implements Consumer { private NotifyPatternToTriggerService notifyPatternToTriggerService; + private NotifyServiceInboundPatternService inboundPatternService; private LDNMessageService ldnMessageService; private ConfigurationService configurationService; private ItemService itemService; @@ -67,6 +71,7 @@ public class LDNMessageConsumer implements Consumer { configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); itemService = ContentServiceFactory.getInstance().getItemService(); bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); + inboundPatternService = NotifyServiceFactory.getInstance().getNotifyServiceInboundPatternService(); } @Override @@ -77,36 +82,53 @@ public class LDNMessageConsumer implements Consumer { return; } - createLDNMessages(context, (Item) event.getSubject(context)); + Item item = (Item) event.getSubject(context); + createManualLDNMessages(context, item); + createAutomaticLDNMessages(context, item); } - private void createLDNMessages(Context context, Item item) throws SQLException { + private void createManualLDNMessages(Context context, Item item) throws SQLException, JsonProcessingException { List patternsToTrigger = notifyPatternToTriggerService.findByItem(context, item); - patternsToTrigger.forEach(patternToTrigger -> { - try { - createLDNMessage(context, patternToTrigger); - } catch (Exception e) { - throw new RuntimeException(e); - } - }); - + for (NotifyPatternToTrigger patternToTrigger : patternsToTrigger) { + createLDNMessage(context,patternToTrigger.getItem(), + patternToTrigger.getNotifyService(), patternToTrigger.getPattern()); + } } - private void createLDNMessage(Context context, NotifyPatternToTrigger patternToTrigger) + private void createAutomaticLDNMessages(Context context, Item item) throws SQLException, JsonProcessingException { + + List inboundPatterns = inboundPatternService.findAutomaticPatterns(context); + + for (NotifyServiceInboundPattern inboundPattern : inboundPatterns) { + if (inboundPattern.getConstraint() == null || + evaluateFilter(context, item, inboundPattern.getConstraint())) { + createLDNMessage(context, item, inboundPattern.getNotifyService(), inboundPattern.getPattern()); + } + } + } + + private boolean evaluateFilter(Context context, Item item, String constraint) { + LogicalStatement filter = + new DSpace().getServiceManager().getServiceByName(constraint, LogicalStatement.class); + + return filter != null && filter.getResult(context, item); + } + + private void createLDNMessage(Context context, Item item, NotifyServiceEntity service, String pattern) throws SQLException, JsonMappingException, JsonProcessingException { - LDN ldn = getLDNMessage(patternToTrigger.getPattern()); + LDN ldn = getLDNMessage(pattern); LDNMessageEntity ldnMessage = ldnMessageService.create(context, format("urn:uuid:%s", UUID.randomUUID())); - ldnMessage.setObject(patternToTrigger.getItem()); - ldnMessage.setTarget(patternToTrigger.getNotifyService()); + ldnMessage.setObject(item); + ldnMessage.setTarget(service); ldnMessage.setQueueStatus(LDNMessageEntity.QUEUE_STATUS_QUEUED); ldnMessage.setQueueTimeout(new Date()); - appendGeneratedMessage(ldn, ldnMessage, patternToTrigger.getPattern()); + appendGeneratedMessage(ldn, ldnMessage, pattern); ObjectMapper mapper = new ObjectMapper(); Notification notification = mapper.readValue(ldnMessage.getMessage(), Notification.class); diff --git a/dspace-api/src/main/java/org/dspace/app/ldn/dao/NotifyServiceInboundPatternDao.java b/dspace-api/src/main/java/org/dspace/app/ldn/dao/NotifyServiceInboundPatternDao.java index 32b6497e5b..194d30e795 100644 --- a/dspace-api/src/main/java/org/dspace/app/ldn/dao/NotifyServiceInboundPatternDao.java +++ b/dspace-api/src/main/java/org/dspace/app/ldn/dao/NotifyServiceInboundPatternDao.java @@ -8,6 +8,7 @@ package org.dspace.app.ldn.dao; import java.sql.SQLException; +import java.util.List; import org.dspace.app.ldn.NotifyServiceEntity; import org.dspace.app.ldn.NotifyServiceInboundPattern; @@ -35,4 +36,12 @@ public interface NotifyServiceInboundPatternDao extends GenericDAO findAutomaticPatterns(Context context) throws SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/app/ldn/dao/impl/NotifyServiceInboundPatternDaoImpl.java b/dspace-api/src/main/java/org/dspace/app/ldn/dao/impl/NotifyServiceInboundPatternDaoImpl.java index 829d8ab96a..5168fd0bed 100644 --- a/dspace-api/src/main/java/org/dspace/app/ldn/dao/impl/NotifyServiceInboundPatternDaoImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/ldn/dao/impl/NotifyServiceInboundPatternDaoImpl.java @@ -8,6 +8,7 @@ package org.dspace.app.ldn.dao.impl; import java.sql.SQLException; +import java.util.List; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Root; @@ -42,4 +43,17 @@ public class NotifyServiceInboundPatternDaoImpl )); return uniqueResult(context, criteriaQuery, false, NotifyServiceInboundPattern.class); } + + @Override + public List findAutomaticPatterns(Context context) throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, NotifyServiceInboundPattern.class); + Root inboundPatternRoot = criteriaQuery.from(NotifyServiceInboundPattern.class); + criteriaQuery.select(inboundPatternRoot); + criteriaQuery.where( + criteriaBuilder.equal( + inboundPatternRoot.get(NotifyServiceInboundPattern_.automatic), true) + ); + return list(context, criteriaQuery, false, NotifyServiceInboundPattern.class, -1, -1); + } } diff --git a/dspace-api/src/main/java/org/dspace/app/ldn/service/NotifyServiceInboundPatternService.java b/dspace-api/src/main/java/org/dspace/app/ldn/service/NotifyServiceInboundPatternService.java index a16dc3bb00..8cd92d45dd 100644 --- a/dspace-api/src/main/java/org/dspace/app/ldn/service/NotifyServiceInboundPatternService.java +++ b/dspace-api/src/main/java/org/dspace/app/ldn/service/NotifyServiceInboundPatternService.java @@ -8,6 +8,7 @@ package org.dspace.app.ldn.service; import java.sql.SQLException; +import java.util.List; import org.dspace.app.ldn.NotifyServiceEntity; import org.dspace.app.ldn.NotifyServiceInboundPattern; @@ -35,6 +36,15 @@ public interface NotifyServiceInboundPatternService { NotifyServiceEntity notifyServiceEntity, String pattern) throws SQLException; + /** + * find all automatic notifyServiceInboundPatterns + * + * @param context the context + * @return all automatic notifyServiceInboundPatterns + * @throws SQLException if database error + */ + public List findAutomaticPatterns(Context context) throws SQLException; + /** * create new notifyServiceInboundPattern * diff --git a/dspace-api/src/main/java/org/dspace/app/ldn/service/impl/NotifyServiceInboundPatternServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/ldn/service/impl/NotifyServiceInboundPatternServiceImpl.java index 0ee31b5c1b..c699d9fd03 100644 --- a/dspace-api/src/main/java/org/dspace/app/ldn/service/impl/NotifyServiceInboundPatternServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/ldn/service/impl/NotifyServiceInboundPatternServiceImpl.java @@ -8,6 +8,7 @@ package org.dspace.app.ldn.service.impl; import java.sql.SQLException; +import java.util.List; import org.dspace.app.ldn.NotifyServiceEntity; import org.dspace.app.ldn.NotifyServiceInboundPattern; @@ -33,6 +34,11 @@ public class NotifyServiceInboundPatternServiceImpl implements NotifyServiceInbo return inboundPatternDao.findByServiceAndPattern(context, notifyServiceEntity, pattern); } + @Override + public List findAutomaticPatterns(Context context) throws SQLException { + return inboundPatternDao.findAutomaticPatterns(context); + } + @Override public NotifyServiceInboundPattern create(Context context, NotifyServiceEntity notifyServiceEntity) throws SQLException { diff --git a/dspace-api/src/test/java/org/dspace/app/ldn/LDNMessageConsumerIT.java b/dspace-api/src/test/java/org/dspace/app/ldn/LDNMessageConsumerIT.java index 8ce3b36f96..305261c7c3 100644 --- a/dspace-api/src/test/java/org/dspace/app/ldn/LDNMessageConsumerIT.java +++ b/dspace-api/src/test/java/org/dspace/app/ldn/LDNMessageConsumerIT.java @@ -30,6 +30,7 @@ import org.dspace.builder.CollectionBuilder; import org.dspace.builder.CommunityBuilder; import org.dspace.builder.EPersonBuilder; import org.dspace.builder.NotifyServiceBuilder; +import org.dspace.builder.NotifyServiceInboundPatternBuilder; import org.dspace.builder.WorkspaceItemBuilder; import org.dspace.content.Collection; import org.dspace.content.Item; @@ -159,6 +160,83 @@ public class LDNMessageConsumerIT extends AbstractIntegrationTestWithDatabase { } + @Test + public void testLDNMessageConsumerRequestReviewAutomatic() throws Exception { + context.turnOffAuthorisationSystem(); + + NotifyServiceEntity notifyService = + NotifyServiceBuilder.createNotifyServiceBuilder(context) + .withName("service name") + .withDescription("service description") + .withUrl("https://service.ldn.org/about") + .withLdnUrl("https://service.ldn.org/inbox") + .build(); + + NotifyServiceInboundPatternBuilder.createNotifyServiceInboundPatternBuilder(context, notifyService) + .withPattern("request-review") + .withConstraint("simple-demo_filter") + .isAutomatic(true) + .build(); + + //3. a workspace item ready to go + WorkspaceItem workspaceItem = + WorkspaceItemBuilder.createWorkspaceItem(context, collection) + .withTitle("demo Item") + .withIssueDate("2023-11-20") + .withFulltext("test.txt", "test", InputStream.nullInputStream()) + .grantLicense() + .build(); + + WorkflowItem workflowItem = workflowService.start(context, workspaceItem); + Item item = workflowItem.getItem(); + context.dispatchEvents(); + context.restoreAuthSystemState(); + + LDNMessageEntity ldnMessage = + ldnMessageService.findAll(context).stream().findFirst().orElse(null); + + + assertThat(notifyService, matchesNotifyServiceEntity(ldnMessage.getTarget())); + assertEquals(workflowItem.getItem().getID(), ldnMessage.getObject().getID()); + assertEquals(QUEUE_STATUS_QUEUED, ldnMessage.getQueueStatus()); + assertNull(ldnMessage.getOrigin()); + assertNotNull(ldnMessage.getMessage()); + + ObjectMapper mapper = new ObjectMapper(); + Notification notification = mapper.readValue(ldnMessage.getMessage(), Notification.class); + + // check id + assertThat(notification.getId(), containsString("urn:uuid:")); + + // check object + assertEquals(notification.getObject().getId(), + configurationService.getProperty("dspace.ui.url") + "/handle/" + item.getHandle()); + assertEquals(notification.getObject().getIetfCiteAs(), + itemService.getMetadataByMetadataString(item, "dc.identifier.uri").get(0).getValue()); + assertEquals(notification.getObject().getUrl().getId(), + configurationService.getProperty("dspace.ui.url") + "/bitstreams/" + + item.getBundles(Constants.CONTENT_BUNDLE_NAME).get(0).getBitstreams().get(0).getID() + "/download"); + + // check target + assertEquals(notification.getTarget().getId(), notifyService.getUrl()); + assertEquals(notification.getTarget().getInbox(), notifyService.getLdnUrl()); + assertEquals(notification.getTarget().getType(), Set.of("Service")); + + // check origin + assertEquals(notification.getOrigin().getId(), configurationService.getProperty("dspace.ui.url")); + assertEquals(notification.getOrigin().getInbox(), configurationService.getProperty("ldn.notify.inbox")); + assertEquals(notification.getOrigin().getType(), Set.of("Service")); + + // check actor + assertEquals(notification.getActor().getId(), configurationService.getProperty("dspace.ui.url")); + assertEquals(notification.getActor().getName(), configurationService.getProperty("dspace.name")); + assertEquals(notification.getOrigin().getType(), Set.of("Service")); + + // check types + assertEquals(notification.getType(), Set.of("coar-notify:ReviewAction", "Offer")); + + } + @Test public void testLDNMessageConsumerRequestEndorsement() throws Exception { context.turnOffAuthorisationSystem(); From e1e973a56657adf6124a91af0a53e0451f896a8b Mon Sep 17 00:00:00 2001 From: mohamed eskander Date: Wed, 22 Nov 2023 18:05:46 +0200 Subject: [PATCH 2/5] [CST-12752] refactoring and added a new method into ServiceManager --- .../org/dspace/content/ItemFilterServiceImpl.java | 13 ++++--------- .../java/org/dspace/kernel/ServiceManager.java | 9 +++++++++ .../servicemanager/DSpaceServiceManager.java | 15 +++++++++++++++ .../servicemanager/MockServiceManagerSystem.java | 5 +++++ .../utils/servicemanager/ProviderStackTest.java | 5 +++++ 5 files changed, 38 insertions(+), 9 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/ItemFilterServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/ItemFilterServiceImpl.java index 6c1d101c2a..d9deb21d9d 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemFilterServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemFilterServiceImpl.java @@ -8,7 +8,6 @@ package org.dspace.content; import java.util.List; -import java.util.Objects; import java.util.stream.Collectors; import org.dspace.app.ldn.ItemFilter; @@ -38,16 +37,12 @@ public class ItemFilterServiceImpl implements ItemFilterService { @Override public List findAll() { - return serviceManager.getServicesNames() + return serviceManager.getServicesWithNamesByType(LogicalStatement.class) + .keySet() .stream() - .filter(id -> isLogicalStatement(id)) - .map(id -> new ItemFilter(id)) + .sorted() + .map(ItemFilter::new) .collect(Collectors.toList()); } - private boolean isLogicalStatement(String id) { - return Objects.nonNull( - serviceManager.getServiceByName(id, LogicalStatement.class) - ); - } } \ No newline at end of file diff --git a/dspace-services/src/main/java/org/dspace/kernel/ServiceManager.java b/dspace-services/src/main/java/org/dspace/kernel/ServiceManager.java index e4cca677c7..60d723892f 100644 --- a/dspace-services/src/main/java/org/dspace/kernel/ServiceManager.java +++ b/dspace-services/src/main/java/org/dspace/kernel/ServiceManager.java @@ -76,6 +76,15 @@ public interface ServiceManager { */ public List getServicesNames(); + /** + * Get the names of all registered service singletons. By + * convention, the name typically matches the fully qualified class + * name). + * + * @return the list of all current registered services + */ + public Map getServicesWithNamesByType(Class type); + /** * Allows adding singleton services and providers in at runtime or * after the service manager has started up. diff --git a/dspace-services/src/main/java/org/dspace/servicemanager/DSpaceServiceManager.java b/dspace-services/src/main/java/org/dspace/servicemanager/DSpaceServiceManager.java index 6cffa7ee66..313f676c5f 100644 --- a/dspace-services/src/main/java/org/dspace/servicemanager/DSpaceServiceManager.java +++ b/dspace-services/src/main/java/org/dspace/servicemanager/DSpaceServiceManager.java @@ -504,6 +504,21 @@ public final class DSpaceServiceManager implements ServiceManagerSystem { return beanNames; } + @Override + public Map getServicesWithNamesByType(Class type) { + checkRunning(); + + if (type == null) { + throw new IllegalArgumentException("type cannot be null"); + } + + try { + return applicationContext.getBeansOfType(type, true, true); + } catch (BeansException e) { + throw new RuntimeException("Failed to get beans of type (" + type + "): " + e.getMessage(), e); + } + } + @Override public boolean isServiceExists(String name) { checkRunning(); diff --git a/dspace-services/src/test/java/org/dspace/servicemanager/MockServiceManagerSystem.java b/dspace-services/src/test/java/org/dspace/servicemanager/MockServiceManagerSystem.java index aecadcdf02..dc7cd26b51 100644 --- a/dspace-services/src/test/java/org/dspace/servicemanager/MockServiceManagerSystem.java +++ b/dspace-services/src/test/java/org/dspace/servicemanager/MockServiceManagerSystem.java @@ -80,6 +80,11 @@ public class MockServiceManagerSystem implements ServiceManagerSystem { return this.sms.getServicesNames(); } + @Override + public Map getServicesWithNamesByType(Class type) { + return this.sms.getServicesWithNamesByType(type); + } + /* (non-Javadoc) * @see org.dspace.kernel.ServiceManager#isServiceExists(java.lang.String) */ diff --git a/dspace-services/src/test/java/org/dspace/utils/servicemanager/ProviderStackTest.java b/dspace-services/src/test/java/org/dspace/utils/servicemanager/ProviderStackTest.java index 300411c053..47c2b302a7 100644 --- a/dspace-services/src/test/java/org/dspace/utils/servicemanager/ProviderStackTest.java +++ b/dspace-services/src/test/java/org/dspace/utils/servicemanager/ProviderStackTest.java @@ -13,6 +13,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.util.ArrayList; +import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -84,6 +85,10 @@ public class ProviderStackTest { return new ArrayList(); } + public Map getServicesWithNamesByType(Class type) { + return new HashMap<>(); + } + public boolean isServiceExists(String name) { return false; } From dcdfa9a6fca36fab13f1610a13e5f00782274003 Mon Sep 17 00:00:00 2001 From: mohamed eskander Date: Wed, 22 Nov 2023 18:13:26 +0200 Subject: [PATCH 3/5] [CST-12115] updated javadoc of new method --- .../main/java/org/dspace/kernel/ServiceManager.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/dspace-services/src/main/java/org/dspace/kernel/ServiceManager.java b/dspace-services/src/main/java/org/dspace/kernel/ServiceManager.java index 60d723892f..c37b5d9b40 100644 --- a/dspace-services/src/main/java/org/dspace/kernel/ServiceManager.java +++ b/dspace-services/src/main/java/org/dspace/kernel/ServiceManager.java @@ -77,11 +77,14 @@ public interface ServiceManager { public List getServicesNames(); /** - * Get the names of all registered service singletons. By - * convention, the name typically matches the fully qualified class - * name). + * Allows developers to get the desired service singleton by the provided type.
+ * This should return all instantiated objects of the type specified with their names + * (may not all be singletons). * - * @return the list of all current registered services + * @param Class type + * @param type the type for the requested service (this will typically be the interface class but can be concrete + * as well) + * @return map with service's name and service singletons */ public Map getServicesWithNamesByType(Class type); From c514fc7430d40ac3c80698a568954a546024d321 Mon Sep 17 00:00:00 2001 From: mohamed eskander Date: Wed, 22 Nov 2023 18:15:36 +0200 Subject: [PATCH 4/5] [CST-12752] updated javadoc of new method --- .../main/java/org/dspace/kernel/ServiceManager.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/dspace-services/src/main/java/org/dspace/kernel/ServiceManager.java b/dspace-services/src/main/java/org/dspace/kernel/ServiceManager.java index c37b5d9b40..60d723892f 100644 --- a/dspace-services/src/main/java/org/dspace/kernel/ServiceManager.java +++ b/dspace-services/src/main/java/org/dspace/kernel/ServiceManager.java @@ -77,14 +77,11 @@ public interface ServiceManager { public List getServicesNames(); /** - * Allows developers to get the desired service singleton by the provided type.
- * This should return all instantiated objects of the type specified with their names - * (may not all be singletons). + * Get the names of all registered service singletons. By + * convention, the name typically matches the fully qualified class + * name). * - * @param Class type - * @param type the type for the requested service (this will typically be the interface class but can be concrete - * as well) - * @return map with service's name and service singletons + * @return the list of all current registered services */ public Map getServicesWithNamesByType(Class type); From f0e7081827a4481156ae7481e86f2bee906ddc63 Mon Sep 17 00:00:00 2001 From: mohamed eskander Date: Wed, 22 Nov 2023 18:20:09 +0200 Subject: [PATCH 5/5] [CST-12752] updated javadoc of new method --- .../main/java/org/dspace/kernel/ServiceManager.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/dspace-services/src/main/java/org/dspace/kernel/ServiceManager.java b/dspace-services/src/main/java/org/dspace/kernel/ServiceManager.java index 60d723892f..60e932c5d7 100644 --- a/dspace-services/src/main/java/org/dspace/kernel/ServiceManager.java +++ b/dspace-services/src/main/java/org/dspace/kernel/ServiceManager.java @@ -77,10 +77,14 @@ public interface ServiceManager { public List getServicesNames(); /** - * Get the names of all registered service singletons. By - * convention, the name typically matches the fully qualified class - * name). + * Allows developers to get the desired service singleton by the provided type.
+ * This should return all instantiated objects of the type specified with their names + * (may not all be singletons). * + * @param Class type + * @param type the type for the requested service (this will typically be the interface class but can be concrete + * as well) + * @return map with service's name and service singletons * @return the list of all current registered services */ public Map getServicesWithNamesByType(Class type);