FHIR Gateway Examples

 

This page contains example interceptors that can be registered with the FHIR Gateway module.

Pointcuts

 

Here is the state of currently available pointcuts on the FHIR Gateway module.

flowchart TB
    App(["Your application"]):::app
    GwMethod["Gateway Method<br/>Called"]:::step
    Route["Route<br/>Selected"]:::step
    TargetReq@{ shape: procs, label: "Target<br/>Requests" }
    TargetResp@{ shape: procs, label: "Target<br/>Responses" }
    Targets@{ shape: procs, label: "Target FHIR<br/>Endpoints" }

    PostSelectHook["Java Hook (post route selection):<br/>FHIRGW_CREATE_POST_SELECT_ROUTE<br/>FHIRGW_READ_POST_SELECT_ROUTE<br/>FHIRGW_UPDATE_POST_SELECT_ROUTE<br/>FHIRGW_DELETE_POST_SELECT_ROUTE<br/>FHIRGW_SEARCH_POST_SELECT_ROUTE<br/>FHIRGW_OPERATION_POST_SELECT_ROUTE<br/>FHIRGW_TRANSACTION_POST_SELECT_ROUTE<br/>FHIRGW_INSTANCE_HISTORY_POST_SELECT_ROUTE"]:::javahook

    PreInvokeHook["Java Hook (once per target):<br/>FHIRGW_CREATE_TARGET_PREINVOKE<br/>FHIRGW_READ_TARGET_PREINVOKE<br/>FHIRGW_UPDATE_TARGET_PREINVOKE<br/>FHIRGW_DELETE_TARGET_PREINVOKE<br/>FHIRGW_SEARCH_TARGET_PREINVOKE<br/>FHIRGW_SEARCH_PAGE_TARGET_PREINVOKE<br/>FHIRGW_OPERATION_TARGET_PREINVOKE<br/>FHIRGW_TRANSACTION_TARGET_PREINVOKE<br/>FHIRGW_INSTANCE_HISTORY_TARGET_PREINVOKE<br/>FHIRGW_GET_TARGET_PREINVOKE"]:::javahook

    PostInvokeHook["Java Hook (once per target):<br/>FHIRGW_READ_TARGET_POSTINVOKE<br/>FHIRGW_SEARCH_TARGET_POSTINVOKE<br/>FHIRGW_OPERATION_TARGET_POSTINVOKE<br/>FHIRGW_GET_TARGET_POSTINVOKE"]:::javahook

    App -- "GET / POST / PUT / DELETE<br/>/Patient/123" --> GwMethod
    GwMethod --> Route
    Route --> PostSelectHook
    PostSelectHook --> TargetReq
    TargetReq --> PreInvokeHook
    PreInvokeHook --> Targets
    Targets --> TargetResp
    TargetResp --> PostInvokeHook
    PostInvokeHook --> App

    click PostSelectHook "/docs/apidocs/cdr-api-public-java/ca/cdr/api/fhir/interceptor/CdrPointcut.html" "Open CdrPointcut docs (FHIRGW_*_POST_SELECT_ROUTE family)"
    click PreInvokeHook "/docs/apidocs/cdr-api-public-java/ca/cdr/api/fhir/interceptor/CdrPointcut.html" "Open CdrPointcut docs (FHIRGW_*_TARGET_PREINVOKE family)"
    click PostInvokeHook "/docs/apidocs/cdr-api-public-java/ca/cdr/api/fhir/interceptor/CdrPointcut.html" "Open CdrPointcut docs (FHIRGW_*_TARGET_POSTINVOKE family)"

Example: Direct Search based on Parameter Value

 

The following example shows an interceptor that looks for a search parameter for gateway searches and directs them to the appropriate target based on the parameter value. This could be used in cases where the same type of resource is served by multiple targets but additional logic is needed in order to determine which target to actually query.

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

import ca.cdr.api.fhir.interceptor.CdrHook;
import ca.cdr.api.fhir.interceptor.CdrPointcut;
import ca.cdr.api.fhirgw.json.GatewayTargetJson;
import ca.cdr.api.fhirgw.model.SearchRequest;
import ca.uhn.fhir.interceptor.api.Interceptor;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;

/**
 * This interceptor expects Observation searches to contain a mandatory
 * parameter called <code>Category</code>. This parameter may have the
 * values <code>lab</code> or <code>vitals</code> and will direct the
 * search to one target or the other.
 */
@Interceptor
public class ChooseGatewaySearchTargetBasedOnParameterInterceptor {

	@CdrHook(CdrPointcut.FHIRGW_SEARCH_TARGET_PREINVOKE)
	public void hook(SearchRequest theRequest, GatewayTargetJson theTarget, ServletRequestDetails theRequestDetails) {

		// This interceptor only applies to Observation searches
		if (!theRequest.getResourceType().equals("Observation")) {
			return;
		}

		// Look for a parameter on the search request called: category
		String category = theRequest.getParameter("category");

		// Remove the parameter from the request so that we don't pass
		// it to the target servers
		theRequest.removeParameters("category");

		// Depending on the value, only query specific targets
		if ("lab".equals(category)) {
			if (!theTarget.getId().equals("lab_target")) {
				theRequest.setSkip(true);
			}
			return;
		}
		if ("vitals".equals(category)) {
			if (!theTarget.getId().equals("vital_target")) {
				theRequest.setSkip(true);
			}
			return;
		}

		// If the category parameter value was missing or invalid, default to
		// an HTTP 400 Invalid Request response from the gateway
		throw new InvalidRequestException("Missing or invalid required parameter: category");
	}
}

Using this interceptor, the following search URL would be directed only to the Gateway target server with the ID lab_target.

http://fhir.example.com/Observation?category=lab

Example: Modify Target Search based on Previous Target Search

 

This example shows how to modify a search being performed on multiple targets so that the actual query used for the later targets is changed based on the results from the search on the earlier targets.

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

import ca.cdr.api.fhir.interceptor.CdrHook;
import ca.cdr.api.fhir.interceptor.CdrPointcut;
import ca.cdr.api.fhirgw.json.GatewayTargetJson;
import ca.cdr.api.fhirgw.model.ISearchResultsAccumulator;
import ca.cdr.api.fhirgw.model.SearchRequest;
import ca.uhn.fhir.interceptor.api.Interceptor;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.Patient;

import java.util.List;
import java.util.Optional;

/**
 * This interceptor is intended to be used in a FHIR Gateway that is configured with multiple
 * search targets. It uses the results of the first target's search results to inform what the
 * query should look like for the second target.
 *
 * While the exact pattern being used here is obviously a bit contrived, it is a simple
 * demonstration of a pattern that can be useful when you have complicated gateway setups.
 *
 * This interceptor would only be effective if the Gateway Route is configured in non-parallel
 * mode, since the results from the first target will not always be available when the second
 * target is being invoked if the searches are performed in parallel.
 */
@Interceptor
public class GatewayEnrichSearchUsingPreviousTargetResults {

	@CdrHook(CdrPointcut.FHIRGW_SEARCH_TARGET_PREINVOKE)
	public void hook(
			SearchRequest theRequest,
			GatewayTargetJson theTarget,
			ISearchResultsAccumulator theISearchResultsAccumulator,
			ServletRequestDetails theRequestDetails) {

		// We assume there are two targets, one called "target1" and one called "target2". This
		// logic only applies to the second target.
		if (!theTarget.getId().equals("target2")) {
			return;
		}

		/*
		 * For this example, we look for the first patient in the search results, and
		 * then modify the query for the second target based on those results. This
		 * is just an example of the type of logic you might use.
		 */
		List<IBaseResource> target1Results = theISearchResultsAccumulator.getResults("target1");
		Optional<Patient> patient = target1Results.stream()
				.filter(t -> t instanceof Patient)
				.map(t -> (Patient) t)
				.findFirst();

		if (!patient.isPresent()) {
			return;
		}

		// Add a search parameter to the second target search request
		String searchForId = patient.get().getId().replaceAll("^1", "2");
		theRequest.addParameter("_id", searchForId);
	}
}

Example: Modify Target Search Results

 

This example shows an interceptor that modifies search results returned by a FHIR Gateway target. Any changes made by this interceptor will be reflected in the eventual client Gateway response.

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

import ca.cdr.api.fhir.interceptor.CdrHook;
import ca.cdr.api.fhir.interceptor.CdrPointcut;
import ca.cdr.api.fhirgw.json.GatewayTargetJson;
import ca.cdr.api.fhirgw.model.ISearchResultsAccumulator;
import ca.cdr.api.fhirgw.model.SearchResponse;
import ca.uhn.fhir.interceptor.api.Interceptor;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.IdType;

/**
 * This interceptor is intended to be used in a FHIR Gateway that is configured with multiple
 * search targets. It modifies the results of searches from a specific target, changing the
 * way that they will be presented to Gateway clients.
 *
 * In this example, we are simply making a basic change to the ID of the
 * resources being returned. You could make other changes however, such
 * as adding or removing elements, or even removing result resources
 * entirely.
 *
 * If you need to see reults from previous searches in order to inform changes being
 * made here, you can retrieve these from {@literal theSearchResultsAccumulator}.
 */
@Interceptor
public class GatewayEnrichGatewayTargetResponses {

	@CdrHook(CdrPointcut.FHIRGW_SEARCH_TARGET_POSTINVOKE)
	public void hook(
			GatewayTargetJson theTarget,
			ISearchResultsAccumulator theISearchResultsAccumulator,
			SearchResponse theResponse) {

		// We assume there are two targets, one called "target1" and one called "target2". This
		// logic only applies to the second target.
		if (!theTarget.getId().equals("target1")) {
			return;
		}

		// Loop through the results of the search and modify them
		for (IBaseResource next : theResponse.getSearchResults()) {
			IIdType existingId = next.getIdElement();
			IdType newId = new IdType("1000" + existingId.getIdPart());
			next.setId(newId);
		}
	}
}

Example: Modify Target Search Uri

 

This example shows an interceptor that modifies search uri before calling a FHIR Gateway target, using http POST method. Useful when a targeted FHIR server doesn't strictly follow endpoint definitions, for some reason.

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

import ca.cdr.api.fhir.interceptor.CdrHook;
import ca.cdr.api.fhir.interceptor.CdrPointcut;
import ca.cdr.api.fhirgw.json.GatewayTargetJson;
import ca.cdr.api.fhirgw.model.ISearchResultsAccumulator;
import ca.cdr.api.fhirgw.model.SearchRequest;
import ca.uhn.fhir.interceptor.api.Interceptor;
import ca.uhn.fhir.rest.client.api.IClientInterceptor;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.api.IHttpResponse;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;

import java.io.IOException;

/**
 * This interceptor is intended to be used in a FHIR Gateway that is configured with multiple
 * search targets.
 *
 * It modifies the uri used for searches for a specific target.
 * For example, the first target doesn't support usual FHIR endpoint '/_search' when using http POST method,
 * but instead offer the same functionality under '/myCustomSearch', in its FHIR API, for some reason.
 * Note: yep, some FHIR servers use creative endpoints!
 *
 * So in this example, we are simply removing '/_search' from the uri of the target when searching using POST method,
 * and replace it with the expected server endpoint '/myCustomSearch'.
 */
@Interceptor
public class GatewayUpdateTargetUriUsingClientInterceptor {

	@CdrHook(CdrPointcut.FHIRGW_SEARCH_TARGET_PREINVOKE)
	public void hook(
			SearchRequest theRequest,
			GatewayTargetJson theTarget,
			ISearchResultsAccumulator theISearchResultsAccumulator,
			ServletRequestDetails theRequestDetails) {

		// We assume there are multiple targets, and the first one is called "target1".
		// This logic only applies to the first target, that also uses http POST method for searching,
		// as configured in Gateway target json configuration
		if (theTarget.getId().equals("target1") && theTarget.getUseHttpPostForAllSearches()) {

			// in that case, we want to modify the uri used to call the target server
			// using a client interceptor
			theRequest.setClientInterceptor(new IClientInterceptor() {

				@Override
				public void interceptRequest(IHttpRequest theHttpRequest) {

					if (theHttpRequest.getUri().endsWith("/_search")) {
						// assuming there is no other '/_search' string in the uri,
						// this will make the Gateway FHIR client do this call:
						// POST [baseUrl]/myCustomSearch
						String correctedUri = theHttpRequest.getUri().replace("/_search", "/myCustomSearch");
						theHttpRequest.setUri(correctedUri);
					}
				}

				@Override
				public void interceptResponse(IHttpResponse theIHttpResponse) throws IOException {
					// nothing to do here!
				}
			});
		}
	}
}

Example: Search Using Alternate Patient ID

 

In this example, we are using an interceptor to entirely replace the patient reference ID with a different ID in queries made to one of the targets, and then replacing the references in the response from the target. This allows the client to make requests using a different patient ID than the one an individual target knows the patient as.

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

import ca.cdr.api.fhir.interceptor.CdrHook;
import ca.cdr.api.fhir.interceptor.CdrPointcut;
import ca.cdr.api.fhirgw.json.GatewayTargetJson;
import ca.cdr.api.fhirgw.model.ISearchResultsAccumulator;
import ca.cdr.api.fhirgw.model.SearchRequest;
import ca.cdr.api.fhirgw.model.SearchResponse;
import ca.uhn.fhir.interceptor.api.Interceptor;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.Observation;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.apache.commons.lang3.StringUtils.isBlank;

/**
 * This interceptor demonstrates a gateway search where the target uses different
 * resource IDs than the one(s) the client understands.
 */
@Interceptor
public class GatewaySearchUsingAlternateTargetIds {

	private final Map<String, String> myClientIdToTargetId;

	/**
	 * Constructor
	 */
	public GatewaySearchUsingAlternateTargetIds() {

		// For this example, we'll just use a hardcoded map to translate the
		// IDs we receive from the client into the IDs we'll use to communicate
		// with the target. Obviously in a real scenario this would probably
		// be a lookup to something external.
		myClientIdToTargetId = new HashMap<>();
		myClientIdToTargetId.put("100", "AAA");
		myClientIdToTargetId.put("200", "BBB");
	}

	/**
	 * This hook is called before the search is executed against the target server
	 */
	@CdrHook(CdrPointcut.FHIRGW_SEARCH_TARGET_PREINVOKE)
	public void preInvoke(
			SearchRequest theRequest,
			GatewayTargetJson theTarget,
			ISearchResultsAccumulator theISearchResultsAccumulator,
			ServletRequestDetails theRequestDetails) {

		// We assume there are two targets, one called "target1" and one called "target2". This
		// logic only applies to the second target.
		if (!theTarget.getId().equals("target2")) {
			return;
		}

		// This logic only applies to the Observation resource type
		if (!theRequest.getResourceType().equals("Observation")) {
			return;
		}

		// Look for the subject ID in either the "patient" or "subject"
		// URL parameters.
		String patientId = theRequest.getParameter("patient");
		if (isBlank(patientId)) {
			patientId = theRequest.getParameter("subject");
		}
		if (isBlank(patientId)) {
			throw new InvalidRequestException("No patient ID supplied in request");
		}

		// The ID supplied by the client can be in forms like "Patient/100" or just "100"
		// so we'll use a HAPI FHIR IdType structure to extract just the ID Part (100).
		patientId = new IdType(patientId).getIdPart();

		// Lookup the mapping for the patient ID in our map
		String newPatientId = myClientIdToTargetId.get(patientId);
		if (newPatientId == null) {
			throw new InvalidRequestException("No mapping found for patient " + patientId);
		}

		// Replace the existing search parameter with the mapped version
		theRequest.removeParameters("patient");
		theRequest.removeParameters("subject");
		theRequest.addParameter("patient", "Patient/" + newPatientId);

		// Store the original patient ID an an attribute so we can look it up later. Note that
		// we use the ID of the target in the attribute name just to avoid any conflicts if
		// multiple interceptors like this one are registered
		theRequestDetails.setServletAttribute("target2-observation-patientId", patientId);
	}

	/**
	 * This hook is called after the target server has responded, and can be used to manipulate
	 * the results
	 */
	@CdrHook(CdrPointcut.FHIRGW_SEARCH_TARGET_POSTINVOKE)
	public void postInvoke(
			GatewayTargetJson theTarget, SearchResponse theSearchResponse, ServletRequestDetails theRequestDetails) {

		// We assume there are two targets, one called "target1" and one called "target2". This
		// logic only applies to the second target.
		if (!theTarget.getId().equals("target2")) {
			return;
		}

		String patientId = (String) theRequestDetails.getServletAttribute("target2-observation-patientId");
		if (isBlank(patientId)) {
			return;
		}

		// Replace the patient ID in the results we received from "target2" with the
		// original ID the user had searched for. This is important because the
		// client won't be expecting to see references using the internal ID, and also
		// because the authorization service will only allow the client to access
		// patients in compartments it has access to.
		List<IBaseResource> results = theSearchResponse.getSearchResults();
		for (IBaseResource nextResult : results) {
			if (nextResult instanceof Observation) {
				Observation nextObservation = (Observation) nextResult;
				nextObservation.getSubject().setReference("Patient/" + patientId);
			}
		}
	}
}

Example: Add Custom Headers to a GET Target Request

 

The FHIRGW_GET_TARGET_PREINVOKE pointcut is called before the FHIR Gateway sends a plain HTTP GET request to a target server. This occurs during $proxy-link operations, such as when the gateway downloads bulk-exported NDJSON files from a target or from a non-FHIR storage location (for example, files stored in Amazon S3).

Interceptors registered on this pointcut can call addAdditionalHeader() on the GetRequest to inject HTTP headers that will be applied to the outgoing download request. This is useful when the download target requires authentication credentials or other headers that are not part of the standard forwarded request headers.

The following example shows an interceptor that adds a custom authorization header before the gateway downloads exported files via $proxy-link:

import ca.cdr.api.fhir.interceptor.CdrHook;
import ca.cdr.api.fhir.interceptor.CdrPointcut;
import ca.cdr.api.fhirgw.json.GatewayTargetJson;
import ca.cdr.api.fhirgw.model.GetRequest;
import ca.uhn.fhir.interceptor.api.Interceptor;

@Interceptor
public class GatewayGetRequestHeaderInterceptor {

    @CdrHook(CdrPointcut.FHIRGW_GET_TARGET_PREINVOKE)
    public void addCustomHeadersToGetRequest(
            GetRequest theGetRequest,
            GatewayTargetJson theGatewayTargetJson) {

        // Add custom headers that will be included in the HTTP GET request
        // sent to the target server or external storage location.
        // This is commonly used for bearer tokens required by S3 pre-signed
        // URLs or other authenticated download endpoints.
        theGetRequest.addAdditionalHeader("Authorization", "Bearer my-download-token");
        theGetRequest.addAdditionalHeader("X-Request-Source", "SmileCDR-Gateway");
    }
}

When a header name set via addAdditionalHeader() conflicts with a header already forwarded from the original client request, the value set by the interceptor wins. This means FHIRGW_GET_TARGET_PREINVOKE can be used to reliably replace outbound credentials (for example, swapping an inbound Authorization token for a different token required by the download target). The comparison is case-insensitive, so Authorization and authorization are treated as the same header name.

addAdditionalHeader() supports multiple values for the same header name. Calling it twice with the same name (for example addAdditionalHeader("Set-Cookie", "a=1") followed by addAdditionalHeader("Set-Cookie", "a=2")) sends both values on the wire, in insertion order. This is the standard HTTP behaviour for headers that permit multiple field values per RFC 7230 §3.2.2.

Note: An Authorization header set by this interceptor always takes precedence over the gateway target's configured HTTP Basic credentials. When the interceptor sets an Authorization header, the target's Basic credentials are not sent; the target Basic credentials are used only when the interceptor does not supply an Authorization header.

Example: Add Custom Headers to a Bulk Export Operation Request

 

The FHIRGW_OPERATION_TARGET_PREINVOKE pointcut is called before the FHIR Gateway dispatches an operation request to a target server. This includes all gateway operation types — $everything, $export, $davinci-data-export, $export-poll-status, and any custom operations.

Interceptors registered on this pointcut can call addAdditionalHeader() on the OperationRequest to inject HTTP headers into the outbound operation request. This is useful when the target server requires credentials or other headers that differ from those on the original inbound request (for example, an internal API token required by the target server regardless of the client's credential).

The following example shows an interceptor that injects a target-specific authorization token on every outbound operation request, including bulk export operations:

import ca.cdr.api.fhir.interceptor.CdrHook;
import ca.cdr.api.fhir.interceptor.CdrPointcut;
import ca.cdr.api.fhirgw.json.GatewayTargetJson;
import ca.cdr.api.fhirgw.model.OperationRequest;
import ca.uhn.fhir.interceptor.api.Interceptor;

@Interceptor
public class GatewayOperationRequestHeaderInterceptor {

    @CdrHook(CdrPointcut.FHIRGW_OPERATION_TARGET_PREINVOKE)
    public void addCustomHeadersToOperationRequest(
            OperationRequest theOperationRequest,
            GatewayTargetJson theGatewayTargetJson) {

        // Add a header that will be sent to the target server for every
        // operation dispatch, including $export kickoff and $export-poll-status.
        theOperationRequest.addAdditionalHeader("Authorization", "Bearer target-api-token");
    }
}

This pointcut fires once per target per operation dispatch. When the gateway fans out to multiple targets in parallel (for example, a system-level $export routed to two target servers), the pointcut fires once per target.

Example: Starter Gateway interceptor for all FHIRGW_xxx pointcuts

 

The following example shows an interceptor that can be used as a starter Gateway interceptor, implementing a hook method for each available pointcut.

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

import ca.cdr.api.broker.IPublicBrokerSender;
import ca.cdr.api.fhir.interceptor.CdrHook;
import ca.cdr.api.fhir.interceptor.CdrPointcut;
import ca.cdr.api.fhirgw.json.AvailableRoutesJson;
import ca.cdr.api.fhirgw.json.GatewayTargetJson;
import ca.cdr.api.fhirgw.json.MatchedRoutesJson;
import ca.cdr.api.fhirgw.model.HistoryRequest;
import ca.cdr.api.fhirgw.model.ISearchResultsAccumulator;
import ca.cdr.api.fhirgw.model.OperationRequest;
import ca.cdr.api.fhirgw.model.OperationResponse;
import ca.cdr.api.fhirgw.model.ReadRequest;
import ca.cdr.api.fhirgw.model.ReadResponse;
import ca.cdr.api.fhirgw.model.SearchPageRequest;
import ca.cdr.api.fhirgw.model.SearchRequest;
import ca.cdr.api.fhirgw.model.SearchResponse;
import ca.cdr.api.fhirgw.model.TransactionRequest;
import ca.cdr.api.fhirgw.model.UpdateRequest;
import ca.uhn.fhir.interceptor.api.Interceptor;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.util.StopWatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * Sample Gateway Interceptor implementing all Smile CDR FHIRGW_XXX pointcuts.
 * It is intended to be used in FHIR Gateway REST Endpoint module 'Interceptor Bean Types'.
 * Can be used as a starting point for your Gateway interceptor.
 */
@SuppressWarnings({"unused", "EmptyTryBlock"})
@Interceptor
public class GatewayInterceptorTemplate {

	@Autowired
	private IPublicBrokerSender myBrokerSender;

	private static final Logger ourLog = LoggerFactory.getLogger(GatewayInterceptorTemplate.class);

	@CdrHook(CdrPointcut.FHIRGW_READ_TARGET_PREINVOKE)
	public void fhirgwReadTargetPreInvoke(
			ReadRequest theReadRequest,
			GatewayTargetJson theGatewayTargetJson,
			ServletRequestDetails theServletRequestDetails) {

		ourLog.info("Interceptor FHIRGW_READ_TARGET_PREINVOKE - started");
		StopWatch stopWatch = new StopWatch();
		try {
			// your implementation goes here
		} finally {
			ourLog.info("Interceptor FHIRGW_READ_TARGET_PREINVOKE - ended, execution took {}", stopWatch);
		}
	}

	@CdrHook(CdrPointcut.FHIRGW_READ_TARGET_POSTINVOKE)
	public void fhirgwReadTargetPostInvoke(
			ReadRequest theReadRequest,
			ReadResponse theReadResponse,
			GatewayTargetJson theGatewayTargetJson,
			ServletRequestDetails theRequestDetails) {
		ourLog.info("Interceptor FHIRGW_READ_TARGET_POSTINVOKE - started");
		StopWatch stopWatch = new StopWatch();
		try {
			// your implementation goes here
		} finally {
			ourLog.info("Interceptor FHIRGW_READ_TARGET_POSTINVOKE - ended. Execution took {}", stopWatch);
		}
	}

	@CdrHook(CdrPointcut.FHIRGW_SEARCH_TARGET_PREINVOKE)
	public void fhirgwSearchTargetPreInvoke(
			SearchRequest theSearchRequest,
			GatewayTargetJson theGatewayTargetJson,
			ISearchResultsAccumulator theISearchResultsAccumulator,
			ServletRequestDetails theServletRequestDetails) {

		ourLog.info("Interceptor FHIRGW_SEARCH_TARGET_PREINVOKE - started");
		StopWatch stopWatch = new StopWatch();
		try {
			// your implementation goes here
		} finally {
			ourLog.info("Interceptor FHIRGW_SEARCH_TARGET_PREINVOKE - ended, execution took {}", stopWatch);
		}
	}

	@CdrHook(CdrPointcut.FHIRGW_SEARCH_PAGE_TARGET_PREINVOKE)
	public void fhirgwSearchPageTargetPreInvoke(
			SearchPageRequest theSearchPageRequest,
			GatewayTargetJson theGatewayTargetJson,
			ISearchResultsAccumulator theISearchResultsAccumulator,
			ServletRequestDetails theServletRequestDetails) {

		ourLog.info("Interceptor FHIRGW_SEARCH_PAGE_TARGET_PREINVOKE - started");
		StopWatch stopWatch = new StopWatch();
		try {
			// your implementation goes here
		} finally {
			ourLog.info("Interceptor FHIRGW_SEARCH_PAGE_TARGET_PREINVOKE - ended, execution took {}", stopWatch);
		}
	}

	@CdrHook(CdrPointcut.FHIRGW_SEARCH_TARGET_POSTINVOKE)
	public void fhirgwSearchTargetPostInvoke(
			GatewayTargetJson theGatewayTargetJson,
			ISearchResultsAccumulator theISearchResultsAccumulator,
			SearchResponse theSearchResponse,
			ServletRequestDetails theServletRequestDetails) {

		ourLog.info("Interceptor FHIRGW_SEARCH_TARGET_POSTINVOKE - started");
		StopWatch stopWatch = new StopWatch();
		try {
			// your implementation goes here
		} finally {
			ourLog.info("Interceptor FHIRGW_SEARCH_TARGET_POSTINVOKE - ended, execution took {}", stopWatch);
		}
	}

	@CdrHook(CdrPointcut.FHIRGW_OPERATION_TARGET_PREINVOKE)
	public void fhirgwOperationTargetPreInvoke(
			OperationRequest theOperationRequest,
			GatewayTargetJson theGatewayTargetJson,
			ServletRequestDetails theServletRequestDetails) {

		ourLog.info("Interceptor FHIRGW_OPERATION_TARGET_PREINVOKE - started");
		StopWatch stopWatch = new StopWatch();
		try {
			// your implementation goes here
		} finally {
			ourLog.info("Interceptor FHIRGW_OPERATION_TARGET_PREINVOKE - ended, execution took {}", stopWatch);
		}
	}

	@CdrHook(CdrPointcut.FHIRGW_OPERATION_TARGET_POSTINVOKE)
	public void fhirgwOperationTargetPostinvoke(
			OperationRequest theOperationRequest,
			ISearchResultsAccumulator theISearchResultsAccumulator,
			OperationResponse theOperationResponse,
			GatewayTargetJson theGatewayTargetJson,
			ServletRequestDetails theServletRequestDetails) {

		ourLog.info("Interceptor FHIRGW_OPERATION_TARGET_POSTINVOKE - started");
		StopWatch stopWatch = new StopWatch();
		try {
			// your implementation goes here
		} finally {
			ourLog.info("Interceptor FHIRGW_OPERATION_TARGET_POSTINVOKE - ended, execution took {}", stopWatch);
		}
	}

	@CdrHook(CdrPointcut.FHIRGW_UPDATE_POST_SELECT_ROUTE)
	public void fhirgwUpdatePostSelectRoute(
			UpdateRequest theUpdateRequest,
			ServletRequestDetails theRequestDetails,
			MatchedRoutesJson theMatchedRoutes,
			AvailableRoutesJson theAvailableRoutes) {
		ourLog.info("interceptor FHIRGW_UPDATE_POST_SELECT_ROUTE - started");
		StopWatch stopWatch = new StopWatch();
		try {
			// your implementation goes here
		} finally {
			ourLog.info("Interceptor FHIRGW_UPDATE_POST_SELECT_ROUTE - ended, execution took {}", stopWatch);
		}
	}

	@CdrHook(CdrPointcut.FHIRGW_TRANSACTION_POST_SELECT_ROUTE)
	public void fhirgwTransactionPostSelectRout(
			ServletRequestDetails theServletRequestDetails,
			TransactionRequest theTransactionRequest,
			MatchedRoutesJson theMatchedRoutesJson,
			AvailableRoutesJson theAvailableRoutesJson) {
		ourLog.info("interceptor FHIRGW_TRANSACTION_POST_SELECT_ROUTE - started");
		StopWatch stopWatch = new StopWatch();
		try {
			// your implementation goes here
		} finally {
			ourLog.info("Interceptor FHIRGW_TRANSACTION_POST_SELECT_ROUTE - ended, execution took {}", stopWatch);
		}
	}

	@CdrHook(CdrPointcut.FHIRGW_INSTANCE_HISTORY_TARGET_PREINVOKE)
	public void fhirgwInstanceHistoryTargetPreinvoke(
			HistoryRequest theHistoryRequest,
			GatewayTargetJson theGatewayTargetJson,
			ServletRequestDetails theRequestDetails) {
		ourLog.info("interceptor FHIRGW_INSTANCE_HISTORY_TARGET_PREINVOKE - started");
		StopWatch stopWatch = new StopWatch();
		try {
			// your implementation goes here
		} finally {
			ourLog.info("Interceptor FHIRGW_INSTANCE_HISTORY_TARGET_PREINVOKE - ended, execution took {}", stopWatch);
		}
	}

	@CdrHook(CdrPointcut.FHIRGW_INSTANCE_HISTORY_POST_SELECT_ROUTE)
	public void fhirgwInstanceHistoryPostSelectRoute(
			ServletRequestDetails theRequestDetails,
			HistoryRequest theHistoryRequest,
			MatchedRoutesJson theMatchedRoutes,
			AvailableRoutesJson theAvailableRoutes) {
		ourLog.info("interceptor FHIRGW_INSTANCE_HISTORY_POST_SELECT_ROUTE - started");
		StopWatch stopWatch = new StopWatch();
		try {
			// your implementation goes here
		} finally {
			ourLog.info("Interceptor FHIRGW_INSTANCE_HISTORY_POST_SELECT_ROUTE - ended, execution took {}", stopWatch);
		}
	}
}