19.14.1System-to-System Data Exchange Examples

 

This page contains example interceptors that can be registered with System-to-System Data Exchange.

19.14.2Example: Custom Member Match

 

The following interceptor can be used to implement custom patient matching algorithm for the $member-match operation.

/*-
 * #%L
 * Smile CDR - CDR
 * %%
 * Copyright (C) 2016 - 2025 Smile CDR, Inc.
 * %%
 * All rights reserved.
 * #L%
 */
package com.smilecdr.demo.s2sdataexchange;

import ca.cdr.api.fhir.interceptor.CdrHook;
import ca.cdr.api.fhir.interceptor.CdrPointcut;
import ca.cdr.api.fhir.interceptor.MemberMatchRequest;
import ca.uhn.fhir.interceptor.api.Interceptor;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.util.StopWatch;
import org.hl7.fhir.r4.model.Patient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@SuppressWarnings({"unused", "EmptyTryBlock"})
@Interceptor
public class S2SDataExchangeInterceptorTemplate {
	private static final Logger ourLog = LoggerFactory.getLogger(S2SDataExchangeInterceptorTemplate.class);

	@CdrHook(CdrPointcut.MEMBER_MATCH)
	public Patient channelImportMessagePreProcessed(
			MemberMatchRequest theMemberMatchRequest, RequestDetails theRequestDetails) {
		ourLog.info("Interceptor MEMBER_MATCH - started");
		StopWatch stopWatch = new StopWatch();
		try {
			// your implementation goes here
		} finally {
			ourLog.info("Interceptor MEMBER_MATCH - ended, execution took {}", stopWatch);
		}
		// should return a Patient if matching patient is found or null otherwise
		return null;
	}
}

19.14.3Example: Client Auth Pre Token

 

The following interceptor can be used to implement custom authentication for $invoke-export operation. It provides the request to be sent to the default authentication server and allows to return a custom token provided by the interceptor.

The request headers change between tokens to be retrieved from $member-match and $batch-export as the latter includes the member-id for the member that is to be exported.

@Interceptor
public class S2SClientAuthPreTokenInterceptorTemplate {
	private static final Logger ourLog = LoggerFactory.getLogger(S2SClientAuthPreTokenInterceptorTemplate.class);

	@CdrHook(CdrPointcut.CLIENT_AUTH_PRE_TOKEN_REQUEST)
	public OpenIdTokenResponse getToken(HttpRequestBase requestBase) {
		ourLog.info(
				"------------------------------------------------- Interceptor CLIENT_AUTH_PRE_TOKEN_REQUEST - called with\n {}",
				requestBase);

		String myMemberId = "";

		// request base will most likely be an HttpPost.
		if (requestBase instanceof HttpEntityEnclosingRequestBase) {
			HttpEntityEnclosingRequestBase entityRequest = (HttpEntityEnclosingRequestBase) requestBase;
			HttpEntity entity = entityRequest.getEntity();
			if (entity != null) {
				try {
					String body = EntityUtils.toString(entity);
					ourLog.info(
							"------------------------------------------------- Interceptor CLIENT_AUTH_PRE_TOKEN_REQUEST\nRequest form data: {}",
							body);

					List<NameValuePair> params = URLEncodedUtils.parse(body, StandardCharsets.UTF_8);
					for (NameValuePair param : params) {
						if ("member_id".equalsIgnoreCase(param.getName())) {
							ourLog.info("Found member_id: {}", param.getValue());
							myMemberId = param.getValue();
							break;
						}
					}

				} catch (Exception e) {
					ourLog.error("Failed to read form data", e);
				}
			} else {
				ourLog.warn("Request entity is null");
			}
		} else {
			ourLog.warn("Request is not an instance of HttpEntityEnclosingRequestBase");
		}
		// Here is where logic for generating and signing assertions by calling custom OAuth servers should happen
		OpenIdTokenResponse tokenResponse = new OpenIdTokenResponse();
		// adjust input prams
		// go get token
		tokenResponse.setAccessToken("THIS_WOULD_BE_A_TOKEN with member id: '" + myMemberId + "'");

		// returning null as tokenResponse would end up as an error in continuing execution
		return tokenResponse;
	}
}