diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/interceptor/api/Pointcut.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/interceptor/api/Pointcut.java
index ed1b6e7bad2..9551243f5ee 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/interceptor/api/Pointcut.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/interceptor/api/Pointcut.java
@@ -1425,7 +1425,8 @@ public enum Pointcut implements IPointcut {
"org.hl7.fhir.instance.model.api.IBaseResource",
"ca.uhn.fhir.rest.api.server.RequestDetails",
"ca.uhn.fhir.rest.server.servlet.ServletRequestDetails",
- "ca.uhn.fhir.rest.api.server.storage.TransactionDetails"
+ "ca.uhn.fhir.rest.api.server.storage.TransactionDetails",
+ Boolean.class.getName()
),
/**
@@ -1469,7 +1470,8 @@ public enum Pointcut implements IPointcut {
"org.hl7.fhir.instance.model.api.IBaseResource",
"ca.uhn.fhir.rest.api.server.RequestDetails",
"ca.uhn.fhir.rest.server.servlet.ServletRequestDetails",
- "ca.uhn.fhir.rest.api.server.storage.TransactionDetails"
+ "ca.uhn.fhir.rest.api.server.storage.TransactionDetails",
+ Boolean.class.getName()
),
@@ -1508,7 +1510,8 @@ public enum Pointcut implements IPointcut {
"org.hl7.fhir.instance.model.api.IBaseResource",
"ca.uhn.fhir.rest.api.server.RequestDetails",
"ca.uhn.fhir.rest.server.servlet.ServletRequestDetails",
- "ca.uhn.fhir.rest.api.server.storage.TransactionDetails"
+ "ca.uhn.fhir.rest.api.server.storage.TransactionDetails",
+ Boolean.class.getName()
),
/**
@@ -1546,7 +1549,7 @@ public enum Pointcut implements IPointcut {
*
*/
STORAGE_TRANSACTION_PROCESSED(void.class,
- "org.hl7.fhir.instance.model.api.IBaseResource",
+ "org.hl7.fhir.instance.model.api.IBaseBundle",
"ca.uhn.fhir.rest.api.server.storage.DeferredInterceptorBroadcasts",
"ca.uhn.fhir.rest.api.server.RequestDetails",
"ca.uhn.fhir.rest.server.servlet.ServletRequestDetails",
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java
index 02ef443c876..9bdb1a5466f 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java
@@ -1364,7 +1364,8 @@ public abstract class BaseHapiFhirDao extends BaseStora
.add(IBaseResource.class, theResource)
.add(RequestDetails.class, theRequestDetails)
.addIfMatchesType(ServletRequestDetails.class, theRequestDetails)
- .add(TransactionDetails.class, theTransactionDetails);
+ .add(TransactionDetails.class, theTransactionDetails)
+ .add(Boolean.class, theTransactionDetails.isPointcutDeferred(Pointcut.STORAGE_PRECOMMIT_RESOURCE_CREATED));
doCallHooks(theTransactionDetails, theRequestDetails, Pointcut.STORAGE_PRECOMMIT_RESOURCE_UPDATED, hookParams);
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java
index 2d4661baf01..ab4ccbf268c 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java
@@ -376,7 +376,8 @@ public abstract class BaseHapiFhirResourceDao extends B
.add(IBaseResource.class, theResource)
.add(RequestDetails.class, theRequest)
.addIfMatchesType(ServletRequestDetails.class, theRequest)
- .add(TransactionDetails.class, theTransactionDetails);
+ .add(TransactionDetails.class, theTransactionDetails)
+ .add(Boolean.class, theTransactionDetails.isPointcutDeferred(Pointcut.STORAGE_PRECOMMIT_RESOURCE_CREATED));
doCallHooks(theTransactionDetails, theRequest, Pointcut.STORAGE_PRECOMMIT_RESOURCE_CREATED, hookParams);
}
@@ -483,13 +484,11 @@ public abstract class BaseHapiFhirResourceDao extends B
.add(IBaseResource.class, resourceToDelete)
.add(RequestDetails.class, theRequestDetails)
.addIfMatchesType(ServletRequestDetails.class, theRequestDetails)
- .add(TransactionDetails.class, theTransactionDetails);
+ .add(TransactionDetails.class, theTransactionDetails)
+ .add(Boolean.class, theTransactionDetails.isPointcutDeferred(Pointcut.STORAGE_PRECOMMIT_RESOURCE_DELETED));
- if (theTransactionDetails.isAcceptingDeferredInterceptorBroadcasts()) {
- theTransactionDetails.addDeferredInterceptorBroadcast(Pointcut.STORAGE_PRECOMMIT_RESOURCE_DELETED, hookParams);
- } else {
- doCallHooks(theTransactionDetails, theRequestDetails, Pointcut.STORAGE_PRECOMMIT_RESOURCE_DELETED, hookParams);
- }
+
+ doCallHooks(theTransactionDetails, theRequestDetails, Pointcut.STORAGE_PRECOMMIT_RESOURCE_DELETED, hookParams);
DaoMethodOutcome outcome = toMethodOutcome(theRequestDetails, savedEntity, resourceToDelete).setCreated(true);
@@ -597,7 +596,8 @@ public abstract class BaseHapiFhirResourceDao extends B
.add(IBaseResource.class, resourceToDelete)
.add(RequestDetails.class, theRequest)
.addIfMatchesType(ServletRequestDetails.class, theRequest)
- .add(TransactionDetails.class, transactionDetails);
+ .add(TransactionDetails.class, transactionDetails)
+ .add(Boolean.class, transactionDetails.isPointcutDeferred(Pointcut.STORAGE_PRECOMMIT_RESOURCE_DELETED));
doCallHooks(transactionDetails, theRequest, Pointcut.STORAGE_PRECOMMIT_RESOURCE_DELETED, hookParams);
}
});
@@ -688,7 +688,8 @@ public abstract class BaseHapiFhirResourceDao extends B
.add(IBaseResource.class, newVersion)
.add(RequestDetails.class, theRequestDetails)
.addIfMatchesType(ServletRequestDetails.class, theRequestDetails)
- .add(TransactionDetails.class, theTransactionDetails);
+ .add(TransactionDetails.class, theTransactionDetails)
+ .add(Boolean.class, theTransactionDetails.isPointcutDeferred(Pointcut.STORAGE_PRECOMMIT_RESOURCE_UPDATED));
myInterceptorBroadcaster.callHooks(Pointcut.STORAGE_PRESTORAGE_RESOURCE_UPDATED, params);
myInterceptorBroadcaster.callHooks(Pointcut.STORAGE_PRECOMMIT_RESOURCE_UPDATED, params);
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseTransactionProcessor.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseTransactionProcessor.java
index 332cfe0b60b..2fbb28bcaa8 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseTransactionProcessor.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseTransactionProcessor.java
@@ -1030,13 +1030,13 @@ public abstract class BaseTransactionProcessor {
HookParams params = new HookParams()
.add(RequestDetails.class, theRequest)
.addIfMatchesType(ServletRequestDetails.class, theRequest)
- .add(DeferredInterceptorBroadcasts.class, deferredInterceptorBroadcasts);
+ .add(DeferredInterceptorBroadcasts.class, deferredInterceptorBroadcasts)
+ .add(TransactionDetails.class, theTransactionDetails)
+ .add(IBaseBundle.class, theResponse);
JpaInterceptorBroadcaster.doCallHooks(myInterceptorBroadcaster, theRequest, Pointcut.STORAGE_TRANSACTION_PROCESSED, params);
theTransactionDetails.deferredBroadcastProcessingFinished();
-
-
//finishedCallingDeferredInterceptorBroadcasts
return entriesToProcess;
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/TransactionHookTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/TransactionHookTest.java
index c686ef636c2..e52cfbbb9c4 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/TransactionHookTest.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/TransactionHookTest.java
@@ -1,23 +1,34 @@
package ca.uhn.fhir.jpa.dao.r4;
+import ca.uhn.fhir.interceptor.api.HookParams;
import ca.uhn.fhir.interceptor.api.IInterceptorService;
import ca.uhn.fhir.interceptor.api.Pointcut;
+import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
+import ca.uhn.fhir.rest.api.server.storage.DeferredInterceptorBroadcasts;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
import ca.uhn.test.concurrency.PointcutLatch;
+import com.google.common.collect.ListMultimap;
+import org.hl7.fhir.instance.model.api.IBaseBundle;
+import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.DiagnosticReport;
import org.hl7.fhir.r4.model.Observation;
+import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.Reference;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
+import java.util.List;
+
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.matchesPattern;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
public class TransactionHookTest extends BaseJpaR4SystemTest {
@@ -34,26 +45,62 @@ public class TransactionHookTest extends BaseJpaR4SystemTest {
@BeforeEach
public void beforeEach() {
myInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_TRANSACTION_PROCESSED, myPointcutLatch);
+ myInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PRECOMMIT_RESOURCE_CREATED, myPointcutLatch);
+ myInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PRECOMMIT_RESOURCE_UPDATED, myPointcutLatch);
+ myInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PRECOMMIT_RESOURCE_DELETED, myPointcutLatch);
}
@Test
- public void testHookShouldContainParamsForAllCreateUpdateDeleteInvocations() {
+ public void testHookShouldContainParamsForAllCreateUpdateDeleteInvocations() throws InterruptedException {
+
+ String urnReference = "urn:uuid:3bc44de3-069d-442d-829b-f3ef68cae371";
+
+ final Observation obsToDelete = new Observation();
+ obsToDelete.setStatus(Observation.ObservationStatus.FINAL);
+ DaoMethodOutcome daoMethodOutcome = myObservationDao.create(obsToDelete);
+
+ Patient pat1 = new Patient();
+
final Observation obs1 = new Observation();
obs1.setStatus(Observation.ObservationStatus.FINAL);
+ obs1.setSubject(new Reference(urnReference));
Bundle b = new Bundle();
Bundle.BundleEntryComponent bundleEntryComponent = b.addEntry();
+
bundleEntryComponent.setResource(obs1);
- bundleEntryComponent.getRequest().setMethod(Bundle.HTTPVerb.POST);
+ bundleEntryComponent.getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("Observation");
+
+ Bundle.BundleEntryComponent patientComponent = b.addEntry();
+ patientComponent.setFullUrl(urnReference);
+ patientComponent.setResource(pat1);
+ patientComponent.getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("Patient");
- try {
- mySystemDao.transaction(mySrd, b);
- fail();
- } catch (ResourceVersionConflictException e) {
- // good, transaction should not succeed because DiagnosticReport has a reference to the obs2
- }
+ //Delete an observation
+ b.addEntry().getRequest().setMethod(Bundle.HTTPVerb.DELETE).setUrl(daoMethodOutcome.getId().toUnqualifiedVersionless().getValue());
+
+
+ myPointcutLatch.setExpectedCount(4);
+ mySystemDao.transaction(mySrd, b);
+ List hookParams = myPointcutLatch.awaitExpected();
+
+ IBaseBundle bundleResponseParam = hookParams.get(3).get(IBaseBundle.class);
+ DeferredInterceptorBroadcasts broadcastsParam = hookParams.get(0).get(DeferredInterceptorBroadcasts.class);
+ ListMultimap deferredInterceptorBroadcasts = broadcastsParam.getDeferredInterceptorBroadcasts();
+ assertThat(deferredInterceptorBroadcasts.entries(), hasSize(3));
+
+ List createPointcutInvocations = deferredInterceptorBroadcasts.get(Pointcut.STORAGE_PRECOMMIT_RESOURCE_CREATED);
+ assertThat(createPointcutInvocations, hasSize(2));
+
+ IBaseResource firstCreatedResource = createPointcutInvocations.get(0).get(IBaseResource.class);
+ assertTrue(firstCreatedResource instanceof Observation);
+
+ IBaseResource secondCreatedResource = createPointcutInvocations.get(1).get(IBaseResource.class);
+ assertTrue(secondCreatedResource instanceof Patient);
+
+ assertThat(deferredInterceptorBroadcasts.get(Pointcut.STORAGE_PRECOMMIT_RESOURCE_DELETED), hasSize(1));
}
@Test
diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/api/server/storage/TransactionDetails.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/api/server/storage/TransactionDetails.java
index 76a28163313..ac8794b7e00 100644
--- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/api/server/storage/TransactionDetails.java
+++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/api/server/storage/TransactionDetails.java
@@ -32,6 +32,7 @@ import java.util.Collections;
import java.util.Date;
import java.util.EnumSet;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
@@ -194,8 +195,12 @@ public class TransactionDetails {
myDeferredInterceptorBroadcasts.put(thePointcut, theHookParams);
}
- public boolean isPointcutDeferred() {
- return myIsPointcutDeferred;
+ public Boolean isPointcutDeferred(Pointcut thePointcut) {
+ if (myDeferredInterceptorBroadcasts == null) {
+ return false;
+ }
+ List hookParams = myDeferredInterceptorBroadcasts.get(thePointcut);
+ return hookParams != null;
}
public void deferredBroadcastProcessingFinished() {