Skip to content
Open
Original file line number Diff line number Diff line change
Expand Up @@ -1885,6 +1885,9 @@ public enum Pointcut implements IPointcut {
* pulled out of the servlet request. This parameter is identical to the RequestDetails parameter above but will
* only be populated when operating in a RestfulServer implementation. It is provided as a convenience.
* </li>
* <li>
* ca.uhn.fhir.rest.api.server.storage.TransactionDetails - The outer transaction details object (since 8.8.0)
* </li>
* </ul>
* <p>
* Hooks must return an instance of <code>ca.uhn.fhir.jpa.dao.TransactionPrePartitionResponse</code>.
Expand All @@ -1896,7 +1899,8 @@ public enum Pointcut implements IPointcut {
"ca.uhn.fhir.jpa.dao.TransactionPrePartitionResponse",
"ca.uhn.fhir.rest.api.server.RequestDetails",
"ca.uhn.fhir.rest.server.servlet.ServletRequestDetails",
"org.hl7.fhir.instance.model.api.IBaseBundle"),
"org.hl7.fhir.instance.model.api.IBaseBundle",
"ca.uhn.fhir.rest.api.server.storage.TransactionDetails"),

/**
* <b>Storage Hook:</b>
Expand All @@ -1920,6 +1924,9 @@ public enum Pointcut implements IPointcut {
* pulled out of the servlet request. This parameter is identical to the RequestDetails parameter above but will
* only be populated when operating in a RestfulServer implementation. It is provided as a convenience.
* </li>
* <li>
* ca.uhn.fhir.rest.api.server.storage.TransactionDetails - The outer transaction details object (since 8.8.0)
* </li>
* </ul>
* <p>
* Hooks should return <code>void</code>.
Expand All @@ -1932,7 +1939,8 @@ public enum Pointcut implements IPointcut {
void.class,
"org.hl7.fhir.instance.model.api.IBaseBundle",
"ca.uhn.fhir.rest.api.server.RequestDetails",
"ca.uhn.fhir.rest.server.servlet.ServletRequestDetails"),
"ca.uhn.fhir.rest.server.servlet.ServletRequestDetails",
"ca.uhn.fhir.rest.api.server.storage.TransactionDetails"),

/**
* <b>Storage Hook:</b>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
type: add
issue: 7341
title: "When processing a FHIR transaction, the TransactionDetails object
is now created earlier and made available to interceptor hooks. Thanks
to Elliott Lavy for the contribution!"
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import ca.uhn.fhir.interceptor.executor.InterceptorService;
import ca.uhn.fhir.jpa.dao.r5.FhirSystemDaoTransactionPartitionR5Test;
import ca.uhn.fhir.model.api.StorageResponseCodeEnum;
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
import ca.uhn.fhir.test.utilities.ITestDataBuilder;
import ca.uhn.fhir.util.BundleBuilder;
import org.hl7.fhir.instance.model.api.IBaseResource;
Expand Down Expand Up @@ -46,7 +47,8 @@ public class TransactionPartitionProcessorTest implements ITestDataBuilder {
@BeforeEach
public void beforeEach() {
myInterceptorBroadcaster.registerInterceptor(myInterceptor);
mySvc = new TransactionPartitionProcessor<>(myTransactionProcessor, myFhirContext, newSrd(), false, myInterceptorBroadcaster, "transaction");
mySvc = new TransactionPartitionProcessor<>(myTransactionProcessor, myFhirContext, newSrd(), false, myInterceptorBroadcaster,
"transaction", new TransactionDetails());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,8 @@ public <BUNDLE extends IBaseBundle> BUNDLE transaction(
RequestDetails theRequestDetails, BUNDLE theRequest, boolean theNestedMode) {
String actionName = "Transaction";

TransactionDetails transactionDetails = new TransactionDetails();

IInterceptorBroadcaster compositeBroadcaster =
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequestDetails);

Expand All @@ -248,18 +250,26 @@ public <BUNDLE extends IBaseBundle> BUNDLE transaction(
HookParams params = new HookParams()
.add(RequestDetails.class, theRequestDetails)
.addIfMatchesType(ServletRequestDetails.class, theRequestDetails)
.add(IBaseBundle.class, theRequest);
.add(IBaseBundle.class, theRequest)
.add(TransactionDetails.class, transactionDetails);
compositeBroadcaster.callHooks(Pointcut.STORAGE_TRANSACTION_PROCESSING, params);
}

IBaseBundle response;
// Interceptor call: STORAGE_TRANSACTION_PRE_PARTITION
if (compositeBroadcaster.hasHooks(Pointcut.STORAGE_TRANSACTION_PRE_PARTITION)) {
response = new TransactionPartitionProcessor<BUNDLE>(
this, myContext, theRequestDetails, theNestedMode, compositeBroadcaster, actionName)
this,
myContext,
theRequestDetails,
theNestedMode,
compositeBroadcaster,
actionName,
transactionDetails)
.execute(theRequest);
} else {
response = processTransactionAsSubRequest(theRequestDetails, theRequest, actionName, theNestedMode);
response = processTransactionAsSubRequest(
theRequestDetails, transactionDetails, theRequest, actionName, theNestedMode);
}

List<IBase> entries = myVersionAdapter.getEntries(response);
Expand Down Expand Up @@ -398,12 +408,6 @@ private Date getLastModified(IBaseResource theRes) {
return theRes.getMeta().getLastUpdated();
}

IBaseBundle processTransactionAsSubRequest(
RequestDetails theRequestDetails, IBaseBundle theRequest, String theActionName, boolean theNestedMode) {
return processTransactionAsSubRequest(
theRequestDetails, new TransactionDetails(), theRequest, theActionName, theNestedMode);
}

IBaseBundle processTransactionAsSubRequest(
RequestDetails theRequestDetails,
TransactionDetails theTransactionDetails,
Expand Down Expand Up @@ -2615,17 +2619,20 @@ private void processBatchEntry() {
IInterceptorBroadcaster compositeBroadcaster =
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, myRequestDetails);

TransactionDetails transactionDetails = new TransactionDetails();

// Interceptor call: STORAGE_TRANSACTION_PROCESSING
if (compositeBroadcaster.hasHooks(Pointcut.STORAGE_TRANSACTION_PROCESSING)) {
HookParams params = new HookParams()
.add(RequestDetails.class, myRequestDetails)
.addIfMatchesType(ServletRequestDetails.class, myRequestDetails)
.add(IBaseBundle.class, subRequestBundle);
.add(IBaseBundle.class, subRequestBundle)
.add(TransactionDetails.class, transactionDetails);
compositeBroadcaster.callHooks(Pointcut.STORAGE_TRANSACTION_PROCESSING, params);
}

IBaseBundle nextResponseBundle = processTransactionAsSubRequest(
myRequestDetails, subRequestBundle, "Batch sub-request", myNestedMode);
myRequestDetails, transactionDetails, subRequestBundle, "Batch sub-request", myNestedMode);

IBase subResponseEntry =
(IBase) myVersionAdapter.getEntries(nextResponseBundle).get(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public class TransactionPartitionProcessor<BUNDLE extends IBaseBundle> {
private final String myActionName;
private final FhirContext myFhirContext;
private final BaseTransactionProcessor myTransactionProcessor;
private final TransactionDetails myTransactionDetails;

/**
* Constructor
Expand All @@ -77,13 +78,15 @@ public TransactionPartitionProcessor(
RequestDetails theRequestDetails,
boolean theNestedMode,
IInterceptorBroadcaster theCompositeBroadcaster,
String theActionName) {
String theActionName,
TransactionDetails theTransactionDetails) {
myTransactionProcessor = theTransactionProcessor;
myFhirContext = theFhirContext;
myRequestDetails = theRequestDetails;
myNestedMode = theNestedMode;
myInterceptorBroadcaster = theCompositeBroadcaster;
myActionName = theActionName;
myTransactionDetails = theTransactionDetails;
}

/**
Expand All @@ -105,7 +108,8 @@ public BUNDLE execute(BUNDLE theRequest) {
HookParams hookParams = new HookParams()
.add(RequestDetails.class, myRequestDetails)
.addIfMatchesType(ServletRequestDetails.class, myRequestDetails)
.add(IBaseBundle.class, theRequest);
.add(IBaseBundle.class, theRequest)
.add(TransactionDetails.class, myTransactionDetails);
TransactionPrePartitionResponse partitionResponse =
(TransactionPrePartitionResponse) myInterceptorBroadcaster.callHooksAndReturnObject(
Pointcut.STORAGE_TRANSACTION_PRE_PARTITION, hookParams);
Expand Down Expand Up @@ -197,7 +201,7 @@ private BUNDLE processPartitionedBundles(BUNDLE theOriginalBundle, List<IBaseBun
}

IBaseBundle singlePartitionResponse = myTransactionProcessor.processTransactionAsSubRequest(
myRequestDetails, transactionDetails, singlePartitionRequest, myActionName, myNestedMode);
myRequestDetails, myTransactionDetails, singlePartitionRequest, myActionName, myNestedMode);

// Capture any placeholder ID substitutions from this partition
TransactionUtil.TransactionResponse singlePartitionResponseParsed =
Expand Down
Loading