Examples: FHIR Storage - Smile CDR Documentation
FHIR Storage Examples
This page contains example interceptors that can be registered with the FHIR Storage module.
Example: Response Attribute Enhancement
The following example shows an interceptor that can be used to enhance resources that are submitted for update by a client. In this example, for every time that a Patient resource is created or updated, we are calling a REST MDM service to fetch an EUID (an enterprise identifier for a Patient). We are then adding this EUID as an additional identifier on the list of patient identifiers.
/*-
* #%L
* Smile CDR - CDR
* %%
* Copyright (C) 2016 - 2026 Smile CDR, Inc.
* %%
* All rights reserved.
* #L%
*/
package com.smilecdr.demo.fhirstorage;
import ca.uhn.fhir.interceptor.api.Hook;
import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.Identifier;
import org.hl7.fhir.r4.model.Patient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.converter.json.GsonHttpMessageConverter;
import org.springframework.web.client.RestTemplate;
import java.util.Collections;
import java.util.HashMap;
import java.util.Objects;
/**
* This example interceptor fetches a set of attributes from a third-party
* REST service and uses them to enhance the resource being submitted.
*/
@SuppressWarnings("unchecked")
public class ExampleAttributeEnhancingInterceptor {
private static final Logger ourLog = LoggerFactory.getLogger(ExampleAttributeEnhancingInterceptor.class);
/**
* We are going to treat creates and updates the same way in this example, so the
* create method redirects to the update method.
*/
@Hook(Pointcut.STORAGE_PRESTORAGE_RESOURCE_CREATED)
public void resourcePreCreate(RequestDetails theRequest, IBaseResource theResource) {
handleResource(theResource);
}
/**
* For this example we are overriding the <code>resourcePreUpdate</code>
* method, which will be called when a resource is being updated. There
* are many other methods that can be overridden, but this one is
* appropriate for the desired functionality.
*
* @param theRequest Contains details about the incoming request. You may wish to cast this
* object to a {@link ca.uhn.fhir.rest.server.servlet.ServletRequestDetails},
* which is always possible when running interceptors inside Smile CDR.
* @param theOldResource The previous version of the resource, before this update was
* requested by the client.
* @param theNewResource The new version of the resource as submitted by the client. This
* object can be modified.
*/
@Hook(Pointcut.STORAGE_PRESTORAGE_RESOURCE_UPDATED)
public void resourcePreUpdate(
RequestDetails theRequest, IBaseResource theOldResource, IBaseResource theNewResource) {
handleResource(theNewResource);
}
private void handleResource(IBaseResource theResource) {
// This interceptor only cares about Patient resources
if (!(theResource instanceof Patient)) {
return;
}
Patient patient = (Patient) theResource;
/*
* We want to know the primary identifier, which is the first instance of
* Patient.identifier where identifier.system = "http://example.com/mrn". If the
* client has submitted a resource that does not have such an identifier, this
* is an error, and we will throw a PreconditionFailedException (HTTP 412)
*/
String primaryIdentifier = patient.getIdentifier().stream()
.filter(t -> t.getSystem().equals("http://example.com/mrn"))
.map(Identifier::getValue)
.findFirst()
.orElseThrow(() -> new PreconditionFailedException("No MRN supplied with request"));
// We'll use a system property to pull the port number for this example. If the port
// number won't change across deployments you don't need to do this.
int port = Integer.parseInt(System.getProperty("mqm_query_port"));
// We're going to make a web service call to a simple web service that
// returns a JSON response. There are lots of ways of doing this, but
// in our example we'll make a call using the Spring RestTemplate
RestTemplate restTempate = new RestTemplate();
restTempate.setMessageConverters(Collections.singletonList(new GsonHttpMessageConverter()));
HashMap<String, Object> response = restTempate.getForObject(
"http://localhost:" + port + "/mdmquery?mrn=" + primaryIdentifier, HashMap.class);
Objects.requireNonNull(response);
// We'll log the response. Generally this isn't a good idea in a real
// production system, but it's handy for debugging at first.
ourLog.info("Response: {}", response);
// Grab the existing EUID (identifier with a system of "http://example.com/euid")
// and create one if it doesn't exist
Identifier euidIdentifier = patient.getIdentifier().stream()
.filter(t -> t.getSystem().equals("http://example.com/euid"))
.findFirst()
.orElseGet(patient::addIdentifier);
// Set the identifier value using the web service response
euidIdentifier.setSystem("http://example.com/euid");
euidIdentifier.setValue((String) response.get("euid"));
}
}
Copy
Example: Server-Reserved Tags
The following example shows an interceptor that implements reserved tags. For this example, a reserved tag is a tag that can only be set or removed by the server itself. These tags can not be added or removed by a client, and are hidden from the client as well.
import ca.uhn.fhir.interceptor.api.Hook; import ca.uhn.fhir.interceptor.api.Pointcut; import ca.uhn.fhir.rest.api.server.IPreResourceShowDetails; import ca.uhn.fhir.rest.api.server.RequestDetails; import com.google.common.collect.Sets; import org.apache.commons.lang3.tuple.Pair; import org.hl7.fhir.instance.model.api.IBaseCoding; import org.hl7.fhir.instance.model.api.IBaseResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory;
import java.util.Collections; import java.util.Iterator; import java.util.Set;
/**
- This interceptor implements the concept of "reserved tags", which are resource tags (tags in
Resource.meta.tag) that are reserved for internal system use. This means that:- Clients can not add these tags manually
- Reserved tags are preserved between updates of resources that have them
- The reserved tags are not shown to clients and are filtered before serialization
private static final Logger ourLog = LoggerFactory.getLogger(TagPreservingInterceptor.class);
private Set
/** * Constructor */ public TagPreservingInterceptor() { // This is the list of tags we want to preserve myTagsToPreserve = Collections.unmodifiableSet( Sets.newHashSet(Pair.of("http://my-tags", "tag1"), Pair.of("http://my-tags", "tag2"))); }
/** * When a new resource is being created, don't allow the client to include any reserved tags * * @param theRequest Contains details about the incoming request. You may wish to cast this * object to a {@link ca.uhn.fhir.rest.server.servlet.ServletRequestDetails}, * which is always possible when running interceptors inside Smile CDR. * @param theResource The previous resource being created */ @Hook(value = Pointcut.STORAGE_PRESTORAGE_RESOURCE_CREATED, order = 100) public void resourcePreCreate(RequestDetails theRequest, IBaseResource theResource) { removeReservedTags(theResource); }
// Filter out any reserved tags removeReservedTags(theNewResource);
// Copy tags forward theOldResource.getMeta().getTag().stream() .filter(t -> myTagsToPreserve.contains(Pair.of(t.getSystem(), t.getCode()))) .forEach(t -> theNewResource .getMeta() .addTag() .setSystem(t.getSystem()) .setCode(t.getCode()) .setDisplay(t.getDisplay())); }
/** * Before returning any resource to the client, strip the reserved tags */ @Hook(value = Pointcut.STORAGE_PRESHOW_RESOURCES) public void preShow(IPreResourceShowDetails thePreShowDetails) { for (IBaseResource nextResource : thePreShowDetails) { removeReservedTags(nextResource); } }
private void removeReservedTags(IBaseResource theResource) { for (Iterator<? extends IBaseCoding> iter = theResource.getMeta().getTag().iterator(); iter.hasNext(); ) { IBaseCoding nextTag = iter.next(); String system = nextTag.getSystem(); String code = nextTag.getCode(); if (myTagsToPreserve.contains(Pair.of(system, code))) { iter.remove(); } } } }
Copy
# Example: JavaScript Storage Interceptor
```javascript
function fhirResourcePreCreate(theRequestDetails, theResource) {
if (theResource.name[0].family === "initial-family-name") {
theResource.name[0].family = "after-pre-create";
}
}
function fhirResourceCreated(theRequestDetails, theResource) {
if (theResource.name[0].family === "after-pre-create") {
throw "the resource was created";
}
}
function fhirResourcePreUpdate(theRequestDetails, theOldResource, theNewResource) {
if (theNewResource.resourceType === 'Patient') {
if (theOldResource.name[0].family === 'old-name' && theNewResource.name[0].family === 'new-name') {
theNewResource.name[0].given[0] = 'a-given-name';
}
} else {
Log.info("Unknown resource type " + theNewResource.resourceType);
}
}
function fhirResourceUpdated(theRequestDetails, theOldResource, theNewResource) {
if (theOldResource.name[0].family === 'old-name' && theNewResource.name[0].given[0].toString() === "a-given-name") {
throw "the resource was updated";
}
}
function fhirResourcePreDelete(theRequestDetails, theResource) {
if (theResource.name[0].family === 'removed-family-name') {
theResource.name[0].given[0] = 'b-given-name';
}
}
function fhirResourceDeleted(theRequestDetails, theResource) {
if (theResource.resourceType === 'Patient') {
throw "This patient was deleted";
}
}
Copy
Example: MegaScale Connection Provider
The following example shows an interceptor that is used to provide connection details for a FHIR Storage module configured in MegaScale mode.
import ca.cdr.api.fhir.interceptor.CdrHook; import ca.cdr.api.fhir.interceptor.CdrPointcut; import ca.cdr.api.persistence.megascale.MegaScaleCredentialRequestJson; import ca.cdr.api.persistence.megascale.MegaScaleCredentialResponseJson; import ca.uhn.fhir.interceptor.api.Interceptor; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import org.apache.commons.lang3.StringUtils;
/**
- This interceptor is invoked when initiating a request for a MegaScale
- connection for a specific partition. It returns the associated JDBC
- URL, username and password to use for that partition.
- Responses are cached, so this pointcut will not be repeatedly invoked
- every time a partition is accessed and this interceptor is therefore
- not considered performance critical if latency is incurred.
- Note that using the in-memory H2 databases in this interceptor can cause shard
- connection pools to scale down to zero because the {@code connectionpool.maxlifetime}
- setting defaults to 10 minutes. When this happens, the in-memory databases may
- be closed and garbage-collected, causing database table access errors.
- To prevent this, increase the connection pool idle and lifetime settings. For
- example, add the following properties to your cdr-config file:
- module.persistence.config.db.connectionpool.minidle=2
- module.persistence.config.db.connectionpool.maxlifetime.millis=3600000 */ @Interceptor public class MegaScaleConnectionProvidingInterceptor {
@CdrHook(CdrPointcut.STORAGE_MEGASCALE_PROVIDE_DB_INFO) public MegaScaleCredentialResponseJson provideMegaScaleCredentials(MegaScaleCredentialRequestJson theRequest) {
MegaScaleCredentialResponseJson response; if (theRequest.getPartitionId() != 0) { response = determinePartitionById(theRequest.getPartitionId()); } else if (!StringUtils.isBlank(theRequest.getPartitionName())) { response = determinePartitionByName(theRequest.getPartitionName()); } else { throw new InvalidRequestException("No way to identify this partition!"); } /* * If any additional SQL should be executed in the database when it is * first initialized, it may be added here. The example below shows a * no-op query which does not do anything (and this should be removed * in a real deployment), but you could replace this with a script that * sets permissions or adds placeholders. */ response.addDatabaseInitializationStatement("SELECT 1"); return response; }
/** * You can elect to determine data source selection by tenant name, instead of by partition ID, if you so desire. / private MegaScaleCredentialResponseJson determinePartitionByName(String partitionName) { / * In this example, we'll use one connection URL for tenants "TENANT-A" & "TENANT-C", and * a different connection URL for partitions "TENANT-B" & "TENANT-D". You can group partitions * any way you would like. */ MegaScaleCredentialResponseJson retVal = new MegaScaleCredentialResponseJson(); switch (partitionName) { case "TENANT-A": case "TENANT-C": setConnectionToFirstDatabase(retVal); break; case "TENANT-B": case "TENANT-D": setConnectionToSecondDatabase(retVal); break; default: // Shouldn't happen, and will cause an error if it does } return retVal; }
private void setConnectionToSecondDatabase(MegaScaleCredentialResponseJson retVal) { retVal.setDatabaseUrl("jdbc:h2:mem:ds2"); retVal.setDatabaseUsername("SA"); retVal.setDatabasePassword("SA"); }
private void setConnectionToFirstDatabase(MegaScaleCredentialResponseJson retVal) { retVal.setDatabaseUrl("jdbc:h2:mem:ds1"); retVal.setDatabaseUsername("SA"); retVal.setDatabasePassword("SA"); }
private MegaScaleCredentialResponseJson determinePartitionById(int partitionId) { /* * In this example, we'll use one connection URL for partitions 1 & 3, and * a different connection URL for partitions 2 & 4. You can group partitions * any way you would like. / MegaScaleCredentialResponseJson retVal = new MegaScaleCredentialResponseJson(); switch (partitionId) { case 1: case 3: setConnectionToFirstDatabase(retVal); break; case 2: case 4: setConnectionToSecondDatabase(retVal); break; default: // Shouldn't happen, and will cause an error if it does } / * If any additional SQL should be executed in the database when it is * first initialized, it may be added here. The example below shows a * no-op query which does not do anything (and this should be removed * in a real deployment), but you could replace this with a script that * sets permissions or adds placeholders. */ retVal.addDatabaseInitializationStatement("SELECT 1");
return retVal; } }
Copy
# Example: Starter Storage interceptor for all STORAGE\_xxx pointcuts
The following example shows an interceptor that can be used as a starter Storage interceptor, implementing a hook method for each available pointcut.
import ca.cdr.api.broker.IPublicBrokerSender;
import ca.cdr.api.i18n.ILocalizer;
import ca.cdr.api.transactionlog.ITransactionLogFetchingSvc;
import ca.cdr.api.transactionlog.ITransactionLogStoringSvc;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.interceptor.api.Hook;
import ca.uhn.fhir.interceptor.api.Interceptor;
import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.interceptor.model.ReadPartitionIdRequestDetails;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.interceptor.model.TransactionWriteOperationsDetails;
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.model.DeleteConflictList;
import ca.uhn.fhir.jpa.api.model.ResourceVersionConflictResolutionStrategy;
import ca.uhn.fhir.jpa.interceptor.validation.RepositoryValidatingRuleBuilder;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.rest.api.InterceptorInvocationTimingEnum;
import ca.uhn.fhir.rest.api.server.IPreResourceAccessDetails;
import ca.uhn.fhir.rest.api.server.IPreResourceShowDetails;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.api.server.bulk.BulkExportJobParameters;
import ca.uhn.fhir.rest.api.server.storage.DeferredInterceptorBroadcasts;
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.rest.server.util.ICachedSearchDetails;
import ca.uhn.fhir.util.StopWatch;
import ca.uhn.fhir.validation.ValidationResult;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.PlatformTransactionManager;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
/**
* Sample Storage Interceptor implementing all STORAGE_XXX pointcuts.
* It is indented to be used in FHIR Storage Persistence module 'Interceptor Bean Types'.
* Can be used as a starting point for your storage interceptor.
*
* NOTE ON USING THIS TEMPLATE:
* You should cut and paste whichever parts of this interceptor you need into a
* new class, or remove all the methods and fields you do not need. It is
* inefficient to actually deploy this interceptor with every pointcut declared
* and not actually used.
*/
@SuppressWarnings({"unused", "EmptyTryBlock"})
@Interceptor
public class StorageInterceptorTemplate {
private static final Logger ourLog = LoggerFactory.getLogger(StorageInterceptorTemplate.class);
@Autowired
private IPublicBrokerSender myBrokerSender;
@Autowired
private ITransactionLogFetchingSvc myTransactionLogFetchingSvc;
@Autowired
private ITransactionLogStoringSvc myTransactionLogStoringSvc;
@Autowired
private ILocalizer myLocalizer;
@Autowired
private FhirContext myFhirContext;
@Autowired
private DaoRegistry myDaoRegistry;
@Autowired
private RepositoryValidatingRuleBuilder myRuleBuilder;
@Autowired
private JpaStorageSettings myStorageSettings;
@Autowired
private PlatformTransactionManager myTransactionManager;
@Hook(Pointcut.STORAGE_PRESEARCH_REGISTERED)
public void storagePreSearchRegistered(
ICachedSearchDetails theCachedSearchDetails,
RequestDetails theRequestDetails,
ServletRequestDetails theServletRequestDetails,
SearchParameterMap theSearchParameterMap) {
ourLog.info("Interceptor STORAGE_PRESEARCH_REGISTERED - started");
StopWatch stopWatch = new StopWatch();
try {
// your implementation goes here
} finally {
ourLog.info("Interceptor STORAGE_PRESEARCH_REGISTERED - ended, execution took {}", stopWatch);
}
}
@Hook(Pointcut.STORAGE_PRECHECK_FOR_CACHED_SEARCH)
public boolean storagePreCheckForCachedSearch(
SearchParameterMap theSearchParameterMap,
RequestDetails theRequestDetails,
ServletRequestDetails theServletRequestDetails) {
ourLog.info("Interceptor STORAGE_PRECHECK_FOR_CACHED_SEARCH - started");
StopWatch stopWatch = new StopWatch();
try {
// your implementation goes here
} finally {
ourLog.info("Interceptor STORAGE_PRECHECK_FOR_CACHED_SEARCH - ended, execution took {}", stopWatch);
}
return true;
}
@Hook(Pointcut.STORAGE_PREACCESS_RESOURCES)
public void storagePreAccessResources(
IPreResourceAccessDetails thePreResourceAccessDetails,
RequestDetails theRequestDetails,
ServletRequestDetails theServletRequestDetails) {
ourLog.info("Interceptor STORAGE_PREACCESS_RESOURCES - started");
StopWatch stopWatch = new StopWatch();
try {
// your implementation goes here
} finally {
ourLog.info("Interceptor STORAGE_PREACCESS_RESOURCES - ended, execution took {}", stopWatch);
}
}
@Hook(Pointcut.STORAGE_PRESHOW_RESOURCES)
public void storagePreShowResources(
IPreResourceShowDetails thePreResourceShowDetails,
RequestDetails theRequestDetails,
ServletRequestDetails theServletRequestDetails) {
ourLog.info("Interceptor STORAGE_PRESHOW_RESOURCES - started");
StopWatch stopWatch = new StopWatch();
try {
// your implementation goes here
} finally {
ourLog.info("Interceptor STORAGE_PRESHOW_RESOURCES - ended, execution took {}", stopWatch);
}
}
@Hook(Pointcut.STORAGE_PRESTORAGE_RESOURCE_CREATED)
public void storagePreStorageResourceCreated(
IBaseResource theBaseResource,
RequestDetails theRequestDetails,
ServletRequestDetails theServletRequestDetails,
TransactionDetails theTransactionDetails,
RequestPartitionId theRequestPartitionId) {
ourLog.info("Interceptor STORAGE_PRESTORAGE_RESOURCE_CREATED - started");
StopWatch stopWatch = new StopWatch();
try {
// your implementation goes here
} finally {
ourLog.info("Interceptor STORAGE_PRESTORAGE_RESOURCE_CREATED - ended, execution took {}", stopWatch);
}
}
@Hook(Pointcut.STORAGE_PRESTORAGE_RESOURCE_UPDATED)
public void storagePreStorageResourceUpdated(
IBaseResource theBaseResource,
RequestDetails theRequestDetails,
ServletRequestDetails theServletRequestDetails,
TransactionDetails theTransactionDetails) {
ourLog.info("Interceptor STORAGE_PRESTORAGE_RESOURCE_UPDATED - started");
StopWatch stopWatch = new StopWatch();
try {
// your implementation goes here
} finally {
ourLog.info("Interceptor STORAGE_PRESTORAGE_RESOURCE_UPDATED - ended, execution took {}", stopWatch);
}
}
@Hook(Pointcut.STORAGE_PRESTORAGE_RESOURCE_DELETED)
public void storagePreStorageResourceDeleted(
IBaseResource theBaseResource,
RequestDetails theRequestDetails,
ServletRequestDetails theServletRequestDetails,
TransactionDetails theTransactionDetails) {
ourLog.info("Interceptor STORAGE_PRESTORAGE_RESOURCE_DELETED - started");
StopWatch stopWatch = new StopWatch();
try {
// your implementation goes here
} finally {
ourLog.info("Interceptor STORAGE_PRESTORAGE_RESOURCE_DELETED - ended, execution took {}", stopWatch);
}
}
@Hook(Pointcut.STORAGE_PRECOMMIT_RESOURCE_CREATED)
public void storagePreCommitResourceCreated(
IBaseResource theBaseResource,
RequestDetails theRequestDetails,
ServletRequestDetails theServletRequestDetails,
TransactionDetails theTransactionDetails,
InterceptorInvocationTimingEnum theInterceptorInvocationTimingEnum) {
ourLog.info("Interceptor STORAGE_PRECOMMIT_RESOURCE_CREATED - started");
StopWatch stopWatch = new StopWatch();
try {
// your implementation goes here
} finally {
ourLog.info("Interceptor STORAGE_PRECOMMIT_RESOURCE_CREATED - ended, execution took {}", stopWatch);
}
}
@Hook(Pointcut.STORAGE_PRECOMMIT_RESOURCE_UPDATED)
public void storagePreCommitResourceUpdated(
IBaseResource thePreviousContentBaseResource,
IBaseResource theProposedBaseResource,
RequestDetails theRequestDetails,
ServletRequestDetails theServletRequestDetails,
TransactionDetails theTransactionDetails,
InterceptorInvocationTimingEnum theInterceptorInvocationTimingEnum) {
ourLog.info("Interceptor STORAGE_PRECOMMIT_RESOURCE_UPDATED - started");
StopWatch stopWatch = new StopWatch();
try {
// your implementation goes here
} finally {
ourLog.info("Interceptor STORAGE_PRECOMMIT_RESOURCE_UPDATED - ended, execution took {}", stopWatch);
}
}
@Hook(Pointcut.STORAGE_PRECOMMIT_RESOURCE_DELETED)
public void storagePreCommitResourceDeleted(
IBaseResource theBaseResource,
RequestDetails theRequestDetails,
ServletRequestDetails theServletRequestDetails,
TransactionDetails theTransactionDetails,
InterceptorInvocationTimingEnum theInterceptorInvocationTimingEnum) {
ourLog.info("Interceptor STORAGE_PRECOMMIT_RESOURCE_DELETED - started");
StopWatch stopWatch = new StopWatch();
try {
// your implementation goes here
} finally {
ourLog.info("Interceptor STORAGE_PRECOMMIT_RESOURCE_DELETED - ended, execution took {}", stopWatch);
}
}
@Hook(Pointcut.STORAGE_PRESTORAGE_EXPUNGE_RESOURCE)
public void storagePreStorageExpungeResource(
AtomicInteger theAtomicInteger,
IIdType theIdType,
IBaseResource theBaseResource,
RequestDetails theRequestDetails,
ServletRequestDetails theServletRequestDetails) {
ourLog.info("Interceptor STORAGE_PRESTORAGE_EXPUNGE_RESOURCE - started");
StopWatch stopWatch = new StopWatch();
try {
// your implementation goes here
} finally {
ourLog.info("Interceptor STORAGE_PRESTORAGE_EXPUNGE_RESOURCE - ended, execution took {}", stopWatch);
}
}
@Hook(Pointcut.STORAGE_PRESTORAGE_EXPUNGE_EVERYTHING)
public void storagePartitionSelected(
AtomicInteger theAtomicInteger,
RequestDetails theRequestDetails,
ServletRequestDetails theServletRequestDetails) {
ourLog.info("Interceptor STORAGE_PRESTORAGE_EXPUNGE_EVERYTHING - started");
StopWatch stopWatch = new StopWatch();
try {
// your implementation goes here
} finally {
ourLog.info("Interceptor STORAGE_PRESTORAGE_EXPUNGE_EVERYTHING - ended, execution took {}", stopWatch);
}
}
@Hook(Pointcut.STORAGE_PRE_DELETE_EXPUNGE_PID_LIST)
public void storagePreDeleteExpungePidList(
String theResourceType,
List<Long> theResourcePidList,
AtomicLong theAtomicLong,
RequestDetails theRequestDetails,
ServletRequestDetails theServletRequestDetails) {
ourLog.info("Interceptor STORAGE_PRE_DELETE_EXPUNGE_PID_LIST - started");
StopWatch stopWatch = new StopWatch();
try {
// your implementation goes here
} finally {
ourLog.info("Interceptor STORAGE_PRE_DELETE_EXPUNGE_PID_LIST - ended, execution took {}", stopWatch);
}
}
@Hook(Pointcut.STORAGE_PRE_DELETE_EXPUNGE)
public void storagePreDeleteExpunge(
RequestDetails theRequestDetails, ServletRequestDetails theServletRequestDetails, String theUrl) {
ourLog.info("Interceptor STORAGE_PRE_DELETE_EXPUNGE - started");
StopWatch stopWatch = new StopWatch();
try {
// your implementation goes here
} finally {
ourLog.info("Interceptor STORAGE_PRE_DELETE_EXPUNGE - ended, execution took {}", stopWatch);
}
}
@Hook(Pointcut.STORAGE_CASCADE_DELETE)
public void storageCascadeDelete(
RequestDetails theRequestDetails,
ServletRequestDetails theServletRequestDetails,
DeleteConflictList theDeleteConflictList,
IBaseResource theBaseResource) {
ourLog.info("Interceptor STORAGE_CASCADE_DELETE - started");
StopWatch stopWatch = new StopWatch();
try {
// your implementation goes here
} finally {
ourLog.info("Interceptor STORAGE_CASCADE_DELETE - ended, execution took {}", stopWatch);
}
}
@Hook(Pointcut.STORAGE_PARTITION_IDENTIFY_CREATE)
public RequestPartitionId storagePartitionIdentifyCreate(
IBaseResource theBaseResource,
RequestDetails theRequestDetails,
ServletRequestDetails theServletRequestDetails) {
ourLog.info("Interceptor STORAGE_PARTITION_IDENTIFY_CREATE - started");
StopWatch stopWatch = new StopWatch();
try {
// your implementation goes here
} finally {
ourLog.info("Interceptor STORAGE_PARTITION_IDENTIFY_CREATE - ended, execution took {}", stopWatch);
}
return null;
}
@Hook(Pointcut.STORAGE_PARTITION_IDENTIFY_READ)
public RequestPartitionId storagePartitionIdentifyRead(
RequestDetails theRequestDetails,
ServletRequestDetails theServletRequestDetails,
ReadPartitionIdRequestDetails theReadPartitionIdRequestDetails) {
ourLog.info("Interceptor STORAGE_PARTITION_IDENTIFY_READ - started");
StopWatch stopWatch = new StopWatch();
try {
// your implementation goes here
} finally {
ourLog.info("Interceptor STORAGE_PARTITION_IDENTIFY_READ - ended, execution took {}", stopWatch);
}
return null;
}
@Hook(Pointcut.STORAGE_PARTITION_SELECTED)
public void storagePartitionSelected(
RequestPartitionId theRequestPartitionId,
RequestDetails theRequestDetails,
ServletRequestDetails theServletRequestDetails,
RuntimeResourceDefinition theRuntimeResourceDefinition) {
ourLog.info("Interceptor STORAGE_PARTITION_SELECTED - started");
StopWatch stopWatch = new StopWatch();
try {
// your implementation goes here
} finally {
ourLog.info("Interceptor STORAGE_PARTITION_SELECTED - ended, execution took {}", stopWatch);
}
}
@Hook(Pointcut.STORAGE_TRANSACTION_PROCESSED)
public void storageTransactionProcessed(
IBaseBundle theBaseBundle,
DeferredInterceptorBroadcasts theDeferredInterceptorBroadcasts,
RequestDetails theRequestDetails,
ServletRequestDetails theServletRequestDetails,
TransactionDetails theTransactionDetails) {
ourLog.info("Interceptor STORAGE_TRANSACTION_PROCESSED - started");
StopWatch stopWatch = new StopWatch();
try {
// your implementation goes here
} finally {
ourLog.info("Interceptor STORAGE_TRANSACTION_PROCESSED - ended, execution took {}", stopWatch);
}
}
@Hook(Pointcut.STORAGE_INITIATE_BULK_EXPORT)
public void storageInitiateBulkExport(
BulkExportJobParameters theBulkDataExportOptions,
RequestDetails theRequestDetails,
ServletRequestDetails theServletRequestDetails) {
ourLog.info("Interceptor STORAGE_INITIATE_BULK_EXPORT - started");
StopWatch stopWatch = new StopWatch();
try {
// your implementation goes here
} finally {
ourLog.info("Interceptor STORAGE_INITIATE_BULK_EXPORT - ended, execution took {}", stopWatch);
}
}
@Hook(Pointcut.STORAGE_PRESTORAGE_CLIENT_ASSIGNED_ID)
public void storagePreStorageClientAssignedId(IBaseResource theBaseResource, RequestDetails theRequestDetails) {
ourLog.info("Interceptor STORAGE_PRESTORAGE_CLIENT_ASSIGNED_ID - started");
StopWatch stopWatch = new StopWatch();
try {
// your implementation goes here
} finally {
ourLog.info("Interceptor STORAGE_PRESTORAGE_CLIENT_ASSIGNED_ID - ended, execution took {}", stopWatch);
}
}
@Hook(Pointcut.STORAGE_TRANSACTION_WRITE_OPERATIONS_PRE)
public void storageTransactionWriteOperationsPre(
TransactionWriteOperationsDetails theTransactionWriteOperationsDetails,
TransactionDetails theTransactionDetails) {
ourLog.info("Interceptor STORAGE_TRANSACTION_WRITE_OPERATIONS_PRE - started");
StopWatch stopWatch = new StopWatch();
try {
// your implementation goes here
} finally {
ourLog.info("Interceptor STORAGE_TRANSACTION_WRITE_OPERATIONS_PRE - ended, execution took {}", stopWatch);
}
}
@Hook(Pointcut.STORAGE_TRANSACTION_WRITE_OPERATIONS_POST)
public void storageTransactionWriteOperationsPost(
TransactionWriteOperationsDetails theTransactionWriteOperationsDetails,
TransactionDetails theTransactionDetails) {
ourLog.info("Interceptor STORAGE_TRANSACTION_WRITE_OPERATIONS_POST - started");
StopWatch stopWatch = new StopWatch();
try {
// your implementation goes here
} finally {
ourLog.info("Interceptor STORAGE_TRANSACTION_WRITE_OPERATIONS_POST - ended, execution took {}", stopWatch);
}
}
@Hook(Pointcut.STORAGE_VERSION_CONFLICT)
public ResourceVersionConflictResolutionStrategy storageVersionConflict(
RequestDetails theRequestDetails, ServletRequestDetails theServletRequestDetails) {
ourLog.info("Interceptor STORAGE_VERSION_CONFLICT - started");
StopWatch stopWatch = new StopWatch();
try {
// your implementation goes here
} finally {
ourLog.info("Interceptor STORAGE_VERSION_CONFLICT - ended, execution took {}", stopWatch);
}
return null;
}
// should be called when repository validation is enabled
@Hook(Pointcut.VALIDATION_COMPLETED)
public ValidationResult validationCompleted(
IBaseResource theBaseResource, String theRawBaseResource, ValidationResult theValidationResult) {
ourLog.info("Interceptor VALIDATION_COMPLETED - started");
StopWatch stopWatch = new StopWatch();
try {
// your implementation goes here
} finally {
ourLog.info("Interceptor VALIDATION_COMPLETED - ended, execution took {}", stopWatch);
}
return null;
}
@Hook(Pointcut.INTERCEPTOR_REGISTERED)
public void interceptorRegistered() {
ourLog.info("Interceptor INTERCEPTOR_REGISTERED - started");
StopWatch stopWatch = new StopWatch();
try {
// your implementation goes here
} finally {
ourLog.info("Interceptor INTERCEPTOR_REGISTERED - ended, execution took {}", stopWatch);
}
}
}
Copy
Examples: FHIR Storage
Interceptors
Interceptors Pointcuts Starter Project Examples: FHIR Endpoints Examples: HL7v2 Endpoints Examples: FHIR Storage Examples: FHIR Gateway Examples: FHIR Client Examples: MDM Examples: Subscription Examples: Channel Import Examples: Cluster Manager Examples: App Sphere Examples: System To System Data Exchange 2024.02.01 Migration Guide