Examples: Subscription - Smile CDR Documentation
Subscription Examples
This page contains example interceptors that can be registered with Subscription.
Example: Adding Authorization header
The following interceptor can be used to add any authorization header, like Basic Auth or Bearer token, before calling a REST hook deliverer for each resource delivery message.
/*-
* #%L
* Smile CDR - CDR
* %%
* Copyright (C) 2016 - 2026 Smile CDR, Inc.
* %%
* All rights reserved.
* #L%
*/
package com.smilecdr.demo.subscription;
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.jpa.subscription.model.CanonicalSubscription;
import ca.uhn.fhir.jpa.subscription.model.ResourceDeliveryMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import java.util.Map;
/**
* This class is a Hook Interceptor that is invoked immediately before REST HOOK
* deliveries. It demonstrates a simple OAuth2 Client Credentials flow to dynamically
* retrieve a Bearer token and inject it as an Authorization header
*/
@Interceptor
public class SubscriptionRestHookDynamicHeaderInterceptor {
private static final Logger ourLog = LoggerFactory.getLogger(SubscriptionRestHookDynamicHeaderInterceptor.class);
// TODO: Replace with your OAuth2 token endpoint URL
private static final String TOKEN_ENDPOINT = "https://your-auth-server.example.com/oauth2/token";
// TODO: Replace with your OAuth2 client_id
private static final String CLIENT_ID = "your-client-id";
// TODO: Replace with your OAuth2 client_secret
private static final String CLIENT_SECRET = "your-client-secret";
private final RestTemplate myRestTemplate = new RestTemplate();
/**
* The {@link Pointcut#SUBSCRIPTION_BEFORE_REST_HOOK_DELIVERY} is invoked immediately before each
* REST HOOK subscription delivery.
*
* @param theDeliveryMessage This object contains details about the subscription invocation, including
* the contents of the resource that will be delivered.
* @param theSubscription This object contains details about the subscription, including the delivery endpoint,
* headers to add, etc. A new copy of this object is created for every individual delivery
* so it is fine to modify it, and this will not affect other deliveries or
* subscriptions.
* @return Return <code>true</code> if the subscription should proceed, or <code>false</code> if it
* should be aborted.
*/
@Hook(Pointcut.SUBSCRIPTION_BEFORE_REST_HOOK_DELIVERY)
public boolean beforeRestHookDelivery(
ResourceDeliveryMessage theDeliveryMessage, CanonicalSubscription theSubscription) {
try {
final String accessToken = fetchAccessToken();
theSubscription.addHeader("Authorization: Bearer " + accessToken);
} catch (Exception theException) {
ourLog.error("Failed to fetch access token from {}; aborting subscription delivery", TOKEN_ENDPOINT, theException);
return false;
}
return true;
}
/**
* Performs an OAuth2 Client Credentials grant request
* and returns the raw access token string. This example is using
* client credentials secret flow but it can be updated to use
* client credentials jwt assertion flow
*/
@SuppressWarnings("unchecked")
protected String fetchAccessToken() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
headers.setBasicAuth(CLIENT_ID, CLIENT_SECRET);
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
body.add("grant_type", "client_credentials");
Map<String, Object> response = myRestTemplate.postForObject(
TOKEN_ENDPOINT, new HttpEntity<>(body, headers), Map.class);
if (response == null || !response.containsKey("access_token")) {
throw new RuntimeException("Token endpoint response did not contain an access_token field");
}
return (String) response.get("access_token");
}
}
Copy
Example: Starter Subscription interceptor for all SUBSCRIPTION_xxx pointcuts
The following example shows an interceptor that can be used as a starter Subscription interceptor, implementing a hook method for each available pointcut.
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.jpa.searchparam.matcher.InMemoryMatchResult; import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscription; import ca.uhn.fhir.jpa.subscription.model.ResourceDeliveryMessage; import ca.uhn.fhir.jpa.subscription.model.ResourceModifiedJsonMessage; import ca.uhn.fhir.jpa.subscription.model.ResourceModifiedMessage; import ca.uhn.fhir.util.StopWatch; import org.slf4j.Logger; import org.slf4j.LoggerFactory;
/**
- Sample Subscription Interceptor implementing all SUBSCRIPTION_XXX pointcuts.
- It is intended to be used in Subscription module 'Interceptor Bean Types'.
- Can be used as a starting point for your subscription interceptor. */ @SuppressWarnings({"unused", "EmptyTryBlock"}) @Interceptor public class SubscriptionInterceptorTemplate {
private static final Logger ourLog = LoggerFactory.getLogger(SubscriptionInterceptorTemplate.class);
@Hook(Pointcut.SUBSCRIPTION_AFTER_ACTIVE_SUBSCRIPTION_REGISTERED) public void subscriptionAfterActiveSubscriptionRegistered(CanonicalSubscription theCanonicalSubscription) {
ourLog.info("Interceptor SUBSCRIPTION_AFTER_ACTIVE_SUBSCRIPTION_REGISTERED - started"); StopWatch stopWatch = new StopWatch(); try { // your implementation goes here } finally { ourLog.info( "Interceptor SUBSCRIPTION_AFTER_ACTIVE_SUBSCRIPTION_REGISTERED - ended, execution took {}", stopWatch); } }
@Hook(Pointcut.SUBSCRIPTION_AFTER_ACTIVE_SUBSCRIPTION_UNREGISTERED) public void subscriptionAfterActiveSubscriptionUnregistered() {
ourLog.info("Interceptor SUBSCRIPTION_AFTER_ACTIVE_SUBSCRIPTION_UNREGISTERED - started"); StopWatch stopWatch = new StopWatch(); try { // your implementation goes here } finally { ourLog.info( "Interceptor SUBSCRIPTION_AFTER_ACTIVE_SUBSCRIPTION_UNREGISTERED - ended, execution took {}", stopWatch); } }
@Hook(Pointcut.SUBSCRIPTION_RESOURCE_MODIFIED) public boolean subscriptionResourceModified(ResourceModifiedMessage theResourceModifiedMessage) {
ourLog.info("Interceptor SUBSCRIPTION_RESOURCE_MODIFIED - started"); StopWatch stopWatch = new StopWatch(); try { // your implementation goes here } finally { ourLog.info("Interceptor SUBSCRIPTION_RESOURCE_MODIFIED - ended, execution took {}", stopWatch); } return true; }
@Hook(Pointcut.SUBSCRIPTION_RESOURCE_DID_NOT_MATCH_ANY_SUBSCRIPTIONS) public void subscriptionResourceDidNotMatchAnySubscriptions(ResourceModifiedMessage theResourceModifiedMessage) {
ourLog.info("Interceptor SUBSCRIPTION_RESOURCE_DID_NOT_MATCH_ANY_SUBSCRIPTIONS - started"); StopWatch stopWatch = new StopWatch(); try { // your implementation goes here } finally { ourLog.info( "Interceptor SUBSCRIPTION_RESOURCE_DID_NOT_MATCH_ANY_SUBSCRIPTIONS - ended, execution took {}", stopWatch); } }
@Hook(Pointcut.SUBSCRIPTION_RESOURCE_MATCHED) public boolean subscriptionResourceMatched( CanonicalSubscription theCanonicalSubscription, ResourceDeliveryMessage theResourceDeliveryMessage, InMemoryMatchResult theInMemoryMatchResult) {
ourLog.info("Interceptor SUBSCRIPTION_RESOURCE_MATCHED - started"); StopWatch stopWatch = new StopWatch(); try { // your implementation goes here } finally { ourLog.info("Interceptor SUBSCRIPTION_RESOURCE_MATCHED - ended, execution took {}", stopWatch); } return true; }
@Hook(Pointcut.SUBSCRIPTION_BEFORE_PERSISTED_RESOURCE_CHECKED) public boolean subscriptionBeforePersistedResourceChecked(ResourceModifiedMessage theResourceModifiedMessage) {
ourLog.info("Interceptor SUBSCRIPTION_BEFORE_PERSISTED_RESOURCE_CHECKED - started"); StopWatch stopWatch = new StopWatch(); try { // your implementation goes here } finally { ourLog.info( "Interceptor SUBSCRIPTION_BEFORE_PERSISTED_RESOURCE_CHECKED - ended, execution took {}", stopWatch); } return true; }
@Hook(Pointcut.SUBSCRIPTION_AFTER_PERSISTED_RESOURCE_CHECKED) public void subscriptionAfterPersistedResourceChecked(ResourceModifiedMessage theResourceModifiedMessage) {
ourLog.info("Interceptor SUBSCRIPTION_AFTER_PERSISTED_RESOURCE_CHECKED - started"); StopWatch stopWatch = new StopWatch(); try { // your implementation goes here } finally { ourLog.info( "Interceptor SUBSCRIPTION_AFTER_PERSISTED_RESOURCE_CHECKED - ended, execution took {}", stopWatch); } }
@Hook(Pointcut.SUBSCRIPTION_BEFORE_DELIVERY) public boolean subscriptionBeforeDelivery( CanonicalSubscription theCanonicalSubscription, ResourceDeliveryMessage theResourceDeliveryMessage) {
ourLog.info("Interceptor SUBSCRIPTION_BEFORE_DELIVERY - started"); StopWatch stopWatch = new StopWatch(); try { // your implementation goes here } finally { ourLog.info("Interceptor SUBSCRIPTION_BEFORE_DELIVERY - ended, execution took {}", stopWatch); } return true; }
@Hook(Pointcut.SUBSCRIPTION_AFTER_DELIVERY) public void subscriptionAfterDelivery( CanonicalSubscription theCanonicalSubscription, ResourceDeliveryMessage theResourceDeliveryMessage) {
ourLog.info("Interceptor SUBSCRIPTION_AFTER_DELIVERY - started"); StopWatch stopWatch = new StopWatch(); try { // your implementation goes here } finally { ourLog.info("Interceptor SUBSCRIPTION_AFTER_DELIVERY - ended, execution took {}", stopWatch); } }
@Hook(Pointcut.SUBSCRIPTION_AFTER_DELIVERY_FAILED) public boolean subscriptionAfterDeliveryFailed( ResourceDeliveryMessage theResourceDeliveryMessage, Exception theException) {
ourLog.info("Interceptor SUBSCRIPTION_AFTER_DELIVERY_FAILED - started"); StopWatch stopWatch = new StopWatch(); try { // your implementation goes here } finally { ourLog.info("Interceptor SUBSCRIPTION_AFTER_DELIVERY_FAILED - ended, execution took {}", stopWatch); } return true; }
@Hook(Pointcut.SUBSCRIPTION_BEFORE_REST_HOOK_DELIVERY) public boolean subscriptionBeforeRestHookDelivery( CanonicalSubscription theCanonicalSubscription, ResourceDeliveryMessage theResourceDeliveryMessage) {
ourLog.info("Interceptor SUBSCRIPTION_BEFORE_REST_HOOK_DELIVERY - started"); StopWatch stopWatch = new StopWatch(); try { // your implementation goes here } finally { ourLog.info("Interceptor SUBSCRIPTION_BEFORE_REST_HOOK_DELIVERY - ended, execution took {}", stopWatch); } return true; }
@Hook(Pointcut.SUBSCRIPTION_AFTER_REST_HOOK_DELIVERY) public void subscriptionAfterRestHookDelivery( CanonicalSubscription theCanonicalSubscription, ResourceDeliveryMessage theResourceDeliveryMessage) {
ourLog.info("Interceptor SUBSCRIPTION_AFTER_REST_HOOK_DELIVERY - started"); StopWatch stopWatch = new StopWatch(); try { // your implementation goes here } finally { ourLog.info("Interceptor SUBSCRIPTION_AFTER_REST_HOOK_DELIVERY - ended, execution took {}", stopWatch); } }
@Hook(Pointcut.SUBSCRIPTION_BEFORE_MESSAGE_DELIVERY) public boolean subscriptionBeforeMessageDelivery( CanonicalSubscription theCanonicalSubscription, ResourceDeliveryMessage theResourceDeliveryMessage, ResourceModifiedJsonMessage theResourceModifiedJsonMessage) {
ourLog.info("Interceptor SUBSCRIPTION_BEFORE_MESSAGE_DELIVERY - started"); StopWatch stopWatch = new StopWatch(); try { // your implementation goes here } finally { ourLog.info("Interceptor SUBSCRIPTION_BEFORE_MESSAGE_DELIVERY - ended, execution took {}", stopWatch); } return true; }
@Hook(Pointcut.SUBSCRIPTION_AFTER_MESSAGE_DELIVERY) public void subscriptionAfterMessageDelivery( CanonicalSubscription theCanonicalSubscription, ResourceDeliveryMessage theResourceDeliveryMessage) {
ourLog.info("Interceptor SUBSCRIPTION_AFTER_MESSAGE_DELIVERY - started"); StopWatch stopWatch = new StopWatch(); try { // your implementation goes here } finally { ourLog.info("Interceptor SUBSCRIPTION_AFTER_MESSAGE_DELIVERY - ended, execution took {}", stopWatch); } } }
Copy
[Examples: MDM](/content/docs/interceptors/examples_mdm.html)
Examples: Subscription
Interceptors
[Interceptors](/content/docs/interceptors/interceptors.html)
[Pointcuts](/content/docs/interceptors/pointcuts.html)
[Starter Project](/content/docs/interceptors/starter_project.html)
[Examples: FHIR Endpoints](/content/docs/interceptors/examples_fhir_endpoint.html)
[Examples: HL7v2 Endpoints](/content/docs/interceptors/examples_hl7v2_endpoint.html)
[Examples: FHIR Storage](/content/docs/interceptors/examples_fhir_storage.html)
[Examples: FHIR Gateway](/content/docs/interceptors/examples_fhir_gateway.html)
[Examples: FHIR Client](/content/docs/interceptors/examples_fhir_client.html)
[Examples: MDM](/content/docs/interceptors/examples_mdm.html)
[Examples: Subscription](/content/docs/interceptors/examples_subscription.html)
[Examples: Channel Import](/content/docs/interceptors/examples_channel_import.html)
[Examples: Cluster Manager](/content/docs/interceptors/examples_cluster_manager.html)
[Examples: App Sphere](/content/docs/interceptors/examples_app_sphere.html)
[Examples: System To System Data Exchange](/content/docs/interceptors/examples_s2s_data_exchange.html)
[2024.02.01 Migration Guide](/content/docs/interceptors/jakarta_upgrade.html)
[Examples: Channel Import](/content/docs/interceptors/examples_channel_import.html)