From 3592ec1e786d2856bc0ad053afd0173000282904 Mon Sep 17 00:00:00 2001 From: "Brian M. Long" Date: Fri, 9 Aug 2024 11:48:16 -0400 Subject: [PATCH 1/3] added supports for javax.transaction --- pom.xml | 1 + .../annotations/TransactionalWrapper.java | 104 ++++++++++++++++++ .../aspect/RetryingTransactionAspect.java | 34 +++--- 3 files changed, 122 insertions(+), 17 deletions(-) create mode 100644 src/main/java/com/inteligr8/alfresco/annotations/TransactionalWrapper.java diff --git a/pom.xml b/pom.xml index 6d1b702..afeba53 100644 --- a/pom.xml +++ b/pom.xml @@ -73,6 +73,7 @@ com.inteligr8.alfresco aspectj-platform-module 1.0.0 + amp provided diff --git a/src/main/java/com/inteligr8/alfresco/annotations/TransactionalWrapper.java b/src/main/java/com/inteligr8/alfresco/annotations/TransactionalWrapper.java new file mode 100644 index 0000000..c662e1f --- /dev/null +++ b/src/main/java/com/inteligr8/alfresco/annotations/TransactionalWrapper.java @@ -0,0 +1,104 @@ +package com.inteligr8.alfresco.annotations; + +import java.lang.reflect.Method; + +import org.springframework.transaction.annotation.Isolation; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +public class TransactionalWrapper { + + private Transactional stxl = null; + private javax.transaction.Transactional jtxl = null; + + public TransactionalWrapper(Transactional txl) { + this.stxl = txl; + } + + public TransactionalWrapper(javax.transaction.Transactional txl) { + this.jtxl = txl; + } + + public TransactionalWrapper(Method method) { + this.stxl = method.getAnnotation(Transactional.class); + this.jtxl = method.getAnnotation(javax.transaction.Transactional.class); + } + + public boolean isReadOnly() { + if (this.stxl != null) { + return this.stxl.readOnly(); + } else if (this.jtxl != null) { + return false; + } else { + throw new IllegalStateException("This should never happen"); + } + } + + public Propagation getPropagation() { + if (this.stxl != null) { + return this.stxl.propagation(); + } else if (this.jtxl != null) { + switch (this.jtxl.value()) { + case MANDATORY: + return Propagation.MANDATORY; + case REQUIRED: + return Propagation.REQUIRED; + case REQUIRES_NEW: + return Propagation.REQUIRES_NEW; + case SUPPORTS: + return Propagation.SUPPORTS; + case NOT_SUPPORTED: + return Propagation.NOT_SUPPORTED; + case NEVER: + return Propagation.NEVER; + default: + throw new IllegalStateException("This should never happen"); + } + } else { + throw new IllegalStateException("This should never happen"); + } + } + + public Isolation getIsolation() { + if (this.stxl != null) { + return this.stxl.isolation(); + } else if (this.jtxl != null) { + return Isolation.DEFAULT; + } else { + throw new IllegalStateException("This should never happen"); + } + } + + public int getTimeoutInSeconds() { + if (this.stxl != null) { + return this.stxl.timeout(); + } else if (this.jtxl != null) { + return 0; + } else { + throw new IllegalStateException("This should never happen"); + } + } + + @SuppressWarnings("unchecked") + public Class[] getRollbackFor() { + if (this.stxl != null) { + return this.stxl.rollbackFor(); + } else if (this.jtxl != null) { + return this.jtxl.rollbackOn(); + } else { + throw new IllegalStateException("This should never happen"); + } + } + + @SuppressWarnings("unchecked") + public Class[] getNoRollbackFor() { + if (this.stxl != null) { + return this.stxl.noRollbackFor(); + } else if (this.jtxl != null) { + return this.jtxl.dontRollbackOn(); + } else { + throw new IllegalStateException("This should never happen"); + } + } + +} diff --git a/src/main/java/com/inteligr8/alfresco/annotations/aspect/RetryingTransactionAspect.java b/src/main/java/com/inteligr8/alfresco/annotations/aspect/RetryingTransactionAspect.java index 5de69e4..dd6528c 100644 --- a/src/main/java/com/inteligr8/alfresco/annotations/aspect/RetryingTransactionAspect.java +++ b/src/main/java/com/inteligr8/alfresco/annotations/aspect/RetryingTransactionAspect.java @@ -17,9 +17,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.IllegalTransactionStateException; -import org.springframework.transaction.annotation.Transactional; import com.inteligr8.alfresco.annotations.TransactionalRetryable; +import com.inteligr8.alfresco.annotations.TransactionalWrapper; /** * This aspect implements the @Transactional and @TransactionalRetryable @@ -46,7 +46,7 @@ public class RetryingTransactionAspect { @Autowired private TransactionService txService; - @Pointcut("@annotation(org.springframework.transaction.annotation.Transactional) && execution(* *(..))") + @Pointcut("@annotation(org.springframework.transaction.annotation.Transactional || javax.transaction.Transactional) && execution(* *(..))") public void isTransactionalAnnotated() { } @@ -59,11 +59,11 @@ public class RetryingTransactionAspect { this.logger.trace("retryingTransactional({})", joinPoint); Method method = this.getMethod(joinPoint); - Transactional txl = method.getAnnotation(Transactional.class); + TransactionalWrapper txl = new TransactionalWrapper(method); TransactionalRetryable txtry = method.getAnnotation(TransactionalRetryable.class); if (this.doCreateNewTxContext(txl) || this.isReadStateChange(txl)) { - this.logger.debug("Changing TX context: {} => [ro: {}, new: {}]", AlfrescoTransactionSupport.getTransactionReadState(), txl.readOnly(), txl.propagation()); + this.logger.debug("Changing TX context: {} => [ro: {}, new: {}]", AlfrescoTransactionSupport.getTransactionReadState(), txl.isReadOnly(), txl.getPropagation()); return this.execute(joinPoint, txl, txtry); } else if (this.doCreateNewTxRetryContext(txtry)) { this.logger.debug("Changing TX context: retries: {}", txtry.maxRetries()); @@ -81,11 +81,11 @@ public class RetryingTransactionAspect { return methodSig.getMethod(); } - private boolean isReadStateChange(Transactional txl) { + private boolean isReadStateChange(TransactionalWrapper txl) { if (txl == null) return false; - switch (txl.propagation()) { + switch (txl.getPropagation()) { case NEVER: case NOT_SUPPORTED: case SUPPORTS: @@ -98,9 +98,9 @@ public class RetryingTransactionAspect { case TXN_NONE: return true; case TXN_READ_ONLY: - return !txl.readOnly(); + return !txl.isReadOnly(); case TXN_READ_WRITE: - return txl.readOnly(); + return txl.isReadOnly(); default: throw new IllegalStateException(); } @@ -110,10 +110,10 @@ public class RetryingTransactionAspect { return txtry != null; } - private boolean doCreateNewTxContext(Transactional txl) { + private boolean doCreateNewTxContext(TransactionalWrapper txl) { if (txl == null) { return false; - } else switch (txl.propagation()) { + } else switch (txl.getPropagation()) { case NEVER: switch (AlfrescoTransactionSupport.getTransactionReadState()) { case TXN_NONE: @@ -126,10 +126,10 @@ public class RetryingTransactionAspect { case TXN_NONE: throw new IllegalTransactionStateException("A transaction does not exist where one is mandatory"); case TXN_READ_ONLY: - if (!txl.readOnly()) + if (!txl.isReadOnly()) throw new IllegalTransactionStateException("A read-only transaction exists where a read/write one is mandatory"); case TXN_READ_WRITE: - if (txl.readOnly()) + if (txl.isReadOnly()) throw new IllegalTransactionStateException("A read/write transaction exists where a read-only one is mandatory"); } case SUPPORTS: @@ -145,11 +145,11 @@ public class RetryingTransactionAspect { case REQUIRES_NEW: return true; default: - throw new IllegalTransactionStateException("The transactional propagation is not supported: " + txl.propagation()); + throw new IllegalTransactionStateException("The transactional propagation is not supported: " + txl.getPropagation()); } } - private Object execute(final ProceedingJoinPoint joinPoint, Transactional txl, TransactionalRetryable txtry) throws Throwable { + private Object execute(final ProceedingJoinPoint joinPoint, TransactionalWrapper txl, TransactionalRetryable txtry) throws Throwable { RetryingTransactionCallback rtcallback = new RetryingTransactionCallback() { @Override public Object execute() throws Throwable { @@ -179,12 +179,12 @@ public class RetryingTransactionAspect { if (txtry.incRetryWaitInMillis() > 0) rthelper.setRetryWaitIncrementMs(txtry.incRetryWaitInMillis()); } - if (txl != null && txl.timeout() > 0) - rthelper.setMaxExecutionMs(txl.timeout() * 1000L); + if (txl != null && txl.getTimeoutInSeconds() > 0) + rthelper.setMaxExecutionMs(txl.getTimeoutInSeconds() * 1000L); try { this.logger.trace("source tx: {}", AlfrescoTransactionSupport.getTransactionId()); - boolean readonly = txl != null && txl.readOnly() || txl == null && AlfrescoTransactionSupport.getTransactionReadState() == TxnReadState.TXN_READ_ONLY; + boolean readonly = txl != null && txl.isReadOnly() || txl == null && AlfrescoTransactionSupport.getTransactionReadState() == TxnReadState.TXN_READ_ONLY; return rthelper.doInTransaction(rtcallback, readonly, txl != null); } catch (RuntimeException re) { // attempt to unwrap the exception From 4e64539de2a729ed14caabb7c1924a5f03cb8c6c Mon Sep 17 00:00:00 2001 From: "Brian M. Long" Date: Fri, 9 Aug 2024 11:50:47 -0400 Subject: [PATCH 2/3] correct aspectj module depends --- .../module.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/alfresco/module/com.inteligr8.alfresco.annotations-platform-module/module.properties b/src/main/resources/alfresco/module/com.inteligr8.alfresco.annotations-platform-module/module.properties index 319aecb..f821eae 100644 --- a/src/main/resources/alfresco/module/com.inteligr8.alfresco.annotations-platform-module/module.properties +++ b/src/main/resources/alfresco/module/com.inteligr8.alfresco.annotations-platform-module/module.properties @@ -6,4 +6,4 @@ module.version=${project.version} module.repo.version.min=6.0 #module.repo.version.max= -module.depends.aspectj-platform-module=1.0-* +module.depends.com.inteligr8.alfresco.aspectj-platform-module=1.0-* From f636b22c7603d9c6c44e5e53f34eb4025168f1a6 Mon Sep 17 00:00:00 2001 From: "Brian M. Long" Date: Fri, 9 Aug 2024 13:44:48 -0400 Subject: [PATCH 3/3] fix Transactional handing --- pom.xml | 21 +++++++++++++++++-- .../annotations/TransactionalWrapper.java | 15 ++++++++++--- .../aspect/RetryingTransactionAspect.java | 10 ++++++--- 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index afeba53..a2823af 100644 --- a/pom.xml +++ b/pom.xml @@ -72,9 +72,26 @@ com.inteligr8.alfresco aspectj-platform-module - 1.0.0 + 1.0.1 amp - provided + + + + + org.aspectj + aspectjweaver + ${aspectj.version} + test + + + + + jakarta.transaction + jakarta.transaction-api + + + org.springframework + spring-tx diff --git a/src/main/java/com/inteligr8/alfresco/annotations/TransactionalWrapper.java b/src/main/java/com/inteligr8/alfresco/annotations/TransactionalWrapper.java index c662e1f..41f0397 100644 --- a/src/main/java/com/inteligr8/alfresco/annotations/TransactionalWrapper.java +++ b/src/main/java/com/inteligr8/alfresco/annotations/TransactionalWrapper.java @@ -19,9 +19,18 @@ public class TransactionalWrapper { this.jtxl = txl; } - public TransactionalWrapper(Method method) { - this.stxl = method.getAnnotation(Transactional.class); - this.jtxl = method.getAnnotation(javax.transaction.Transactional.class); + public static TransactionalWrapper wrap(Method method) { + Transactional stxl = method.getAnnotation(Transactional.class); + javax.transaction.Transactional jtxl = method.getAnnotation(javax.transaction.Transactional.class); + if (stxl == null && jtxl == null) { + return null; + } else if (stxl != null) { + return new TransactionalWrapper(stxl); + } else if (jtxl != null) { + return new TransactionalWrapper(jtxl); + } else { + throw new IllegalStateException("This should never happen"); + } } public boolean isReadOnly() { diff --git a/src/main/java/com/inteligr8/alfresco/annotations/aspect/RetryingTransactionAspect.java b/src/main/java/com/inteligr8/alfresco/annotations/aspect/RetryingTransactionAspect.java index dd6528c..2e83d92 100644 --- a/src/main/java/com/inteligr8/alfresco/annotations/aspect/RetryingTransactionAspect.java +++ b/src/main/java/com/inteligr8/alfresco/annotations/aspect/RetryingTransactionAspect.java @@ -46,20 +46,24 @@ public class RetryingTransactionAspect { @Autowired private TransactionService txService; - @Pointcut("@annotation(org.springframework.transaction.annotation.Transactional || javax.transaction.Transactional) && execution(* *(..))") + @Pointcut("@annotation(org.springframework.transaction.annotation.Transactional) && execution(* *(..))") public void isTransactionalAnnotated() { } + @Pointcut("@annotation(javax.transaction.Transactional) && execution(* *(..))") + public void isJtaTransactionalAnnotated() { + } + @Pointcut("@annotation(com.inteligr8.alfresco.annotations.TransactionalRetryable) && execution(* *(..))") public void isTransactionalRetryableAnnotated() { } - @Around("isTransactionalAnnotated() || isTransactionalRetryableAnnotated()") + @Around("isTransactionalAnnotated() || isJtaTransactionalAnnotated() || isTransactionalRetryableAnnotated()") public Object retryingTransactional(ProceedingJoinPoint joinPoint) throws Throwable { this.logger.trace("retryingTransactional({})", joinPoint); Method method = this.getMethod(joinPoint); - TransactionalWrapper txl = new TransactionalWrapper(method); + TransactionalWrapper txl = TransactionalWrapper.wrap(method); TransactionalRetryable txtry = method.getAnnotation(TransactionalRetryable.class); if (this.doCreateNewTxContext(txl) || this.isReadStateChange(txl)) {