diff --git a/core/src/main/java/org/alfresco/util/transaction/TransactionListener.java b/core/src/main/java/org/alfresco/util/transaction/TransactionListener.java index a597f5c05c..6e7c28cfda 100644 --- a/core/src/main/java/org/alfresco/util/transaction/TransactionListener.java +++ b/core/src/main/java/org/alfresco/util/transaction/TransactionListener.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2023 Alfresco Software Limited. + * Copyright (C) 2005-2024 Alfresco Software Limited. * * This file is part of Alfresco * @@ -67,4 +67,14 @@ public interface TransactionListener * be used only for cleaning up resources after a rollback has occurred. */ void afterRollback(); + + /** + * Allows to provide a custom listener's order. + * See {@link org.alfresco.repo.transaction.AlfrescoTransactionSupport#COMMIT_ORDER_NORMAL} + * @return custom order or null for the default one + */ + default Integer getCustomOrder() + { + return null; + } } diff --git a/repository/src/main/java/org/alfresco/repo/event2/EventGenerator.java b/repository/src/main/java/org/alfresco/repo/event2/EventGenerator.java index a6dc0546c4..f6a62ddac6 100644 --- a/repository/src/main/java/org/alfresco/repo/event2/EventGenerator.java +++ b/repository/src/main/java/org/alfresco/repo/event2/EventGenerator.java @@ -2,7 +2,7 @@ * #%L * Alfresco Repository * %% - * Copyright (C) 2005 - 2023 Alfresco Software Limited + * Copyright (C) 2005 - 2024 Alfresco Software Limited * %% * This file is part of the Alfresco software. * If the software was purchased under a paid Alfresco license, the terms of @@ -166,6 +166,11 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin setAssociationBehaviour(BeforeDeleteAssociationPolicy.QNAME, "beforeDeleteAssociation"); } + private boolean isSendingEventBeforeCommitRequired() + { + return eventSender.shouldParticipateInTransaction(); + } + /** * Disable Events2 generated events */ @@ -546,23 +551,40 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin protected class EventTransactionListener extends TransactionListenerAdapter { + @Override + public void beforeCommit(boolean readOnly) + { + if (isSendingEventBeforeCommitRequired()) + { + sendAllEvents(); + } + } + @Override public void afterCommit() { - if (isTransactionCommitted()) + if (!isSendingEventBeforeCommitRequired()) { - try - { - sendEvents(); - } - catch (Exception e) - { - // Must consume the exception to protect other TransactionListeners - LOGGER.error("Unexpected error while sending repository events", e); - } + sendAllEvents(); } } + @Override + public Integer getCustomOrder() + { + return isSendingEventBeforeCommitRequired() ? getBeforeCommitOrder() : getAfterCommitOrder(); + } + + protected Integer getBeforeCommitOrder() + { + return 3; + } + + protected Integer getAfterCommitOrder() + { + return null; + } + /** * @return true if a node transaction is not only active, but also committed with modifications. * This means that a {@link TransactionEntity} object was created. @@ -572,6 +594,21 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin return nodeDAO.getCurrentTransactionCommitTime() != null; } + protected void sendAllEvents() + { + if (isTransactionCommitted()) + { + try + { + sendEvents(); + } catch (Exception e) + { + // Must consume the exception to protect other TransactionListeners + LOGGER.error("Unexpected error while sending repository events", e); + } + } + } + private void sendEvents() { final Consolidators consolidators = getTxnConsolidators(this); @@ -623,10 +660,17 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin final REF entityReference, final CON eventConsolidator, final TriPredicate entityToEventEligibilityVerifier) { final EventInfo eventInfo = getEventInfo(AuthenticationUtil.getFullyAuthenticatedUser()); - transactionService.getRetryingTransactionHelper().doInTransaction((RetryingTransactionCallback) () -> { + if (isSendingEventBeforeCommitRequired()) + { eventSender.accept(() -> createEvent(entityReference, eventConsolidator, eventInfo, entityToEventEligibilityVerifier)); - return null; - }, true, true); + } + else + { + transactionService.getRetryingTransactionHelper().doInTransaction((RetryingTransactionCallback) () -> { + eventSender.accept(() -> createEvent(entityReference, eventConsolidator, eventInfo, entityToEventEligibilityVerifier)); + return null; + }, true, true); + } } /** diff --git a/repository/src/main/java/org/alfresco/repo/event2/EventSender.java b/repository/src/main/java/org/alfresco/repo/event2/EventSender.java index e23aa1692d..8ff7c47a2a 100644 --- a/repository/src/main/java/org/alfresco/repo/event2/EventSender.java +++ b/repository/src/main/java/org/alfresco/repo/event2/EventSender.java @@ -49,4 +49,9 @@ public interface EventSender { //no initialization by default } + + default boolean shouldParticipateInTransaction() + { + return false; + } } diff --git a/repository/src/main/java/org/alfresco/repo/transaction/AlfrescoTransactionSupport.java b/repository/src/main/java/org/alfresco/repo/transaction/AlfrescoTransactionSupport.java index a78e754a0a..14b5a38a03 100644 --- a/repository/src/main/java/org/alfresco/repo/transaction/AlfrescoTransactionSupport.java +++ b/repository/src/main/java/org/alfresco/repo/transaction/AlfrescoTransactionSupport.java @@ -2,7 +2,7 @@ * #%L * Alfresco Repository * %% - * Copyright (C) 2005 - 2016 Alfresco Software Limited + * Copyright (C) 2005 - 2024 Alfresco Software Limited * %% * This file is part of the Alfresco software. * If the software was purchased under a paid Alfresco license, the terms of @@ -253,6 +253,10 @@ public abstract class AlfrescoTransactionSupport extends TransactionSupportUtil { bound = bindListener(listener, COMMIT_ORDER_CACHE); } + else if (listener.getCustomOrder() != null) + { + bound = bindListener(listener, listener.getCustomOrder()); + } else { bound = bindListener(listener, COMMIT_ORDER_NORMAL);