au.csiro.pathling.fhir.TerminologyClient Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of terminology Show documentation
Show all versions of terminology Show documentation
Interact with a FHIR terminology server from Spark.
/*
* Copyright 2023 Commonwealth Scientific and Industrial Research
* Organisation (CSIRO) ABN 41 687 119 230.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package au.csiro.pathling.fhir;
import au.csiro.pathling.config.TerminologyAuthConfiguration;
import au.csiro.pathling.config.TerminologyConfiguration;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.client.api.IRestfulClientFactory;
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
import ca.uhn.fhir.rest.gclient.IOperationUntypedWithInput;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.apache.http.client.HttpClient;
import org.hl7.fhir.r4.model.BooleanType;
import org.hl7.fhir.r4.model.CodeSystem;
import org.hl7.fhir.r4.model.CodeType;
import org.hl7.fhir.r4.model.Parameters;
import org.hl7.fhir.r4.model.StringType;
import org.hl7.fhir.r4.model.UriType;
import org.hl7.fhir.r4.model.ValueSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The client interface to FHIR terminology operations.
*
* @author John Grimes
* @author Piotr Szul
*/
public interface TerminologyClient {
Logger log = LoggerFactory.getLogger(TerminologyClient.class);
/**
* @param url the URL of the value set to validate against
* @param system the system of the code to validate
* @param version the version of the code system to validate against
* @param code the code to validate
* @return a {@link Parameters} resource
* @see ValueSet/$validate-code
*/
@Operation(name = "$validate-code", type = ValueSet.class, idempotent = true)
@Nonnull
Parameters validateCode(
@Nonnull @OperationParam(name = "url") UriType url,
@Nonnull @OperationParam(name = "system") UriType system,
@Nullable @OperationParam(name = "systemVersion") StringType version,
@Nonnull @OperationParam(name = "code") CodeType code
);
/**
* Builds a validate code operation that can be customized and executed later.
*
* @param url the URL of the value set to validate against
* @param system the system of the code to validate
* @param version the version of the code system to validate against
* @param code the code to validate
* @return an {@link IOperationUntypedWithInput} that can be customized and executed later
* @see ValueSet/$validate-code
*/
IOperationUntypedWithInput buildValidateCode(@Nonnull UriType url,
@Nonnull UriType system,
@Nullable StringType version, @Nonnull CodeType code);
/**
* @param url the URL of the concept map to use for translation
* @param system the system of the code to translate
* @param version the version of the code system to translate from
* @param code the code to translate
* @param reverse if true, the translation will be reversed
* @param target the URL of the value set within which the translation is sought
* @return a {@link Parameters} resource
* @see ConceptMap/$translate
*/
@Operation(name = "$translate", type = CodeSystem.class, idempotent = true)
@Nonnull
Parameters translate(
@Nonnull @OperationParam(name = "url") UriType url,
@Nonnull @OperationParam(name = "system") UriType system,
@Nullable @OperationParam(name = "version") StringType version,
@Nonnull @OperationParam(name = "code") CodeType code,
@Nullable @OperationParam(name = "reverse") BooleanType reverse,
@Nullable @OperationParam(name = "target") UriType target
);
/**
* Builds a translate operation that can be customized and executed later.
*
* @param url the URL of the concept map to use for translation
* @param system the system of the code to translate
* @param version the version of the code system to translate from
* @param code the code to translate
* @param reverse if true, the translation will be reversed
* @param target the URL of the value set within which the translation is sought
* @return an {@link IOperationUntypedWithInput} that can be customized and executed later
* @see ConceptMap/$translate
*/
@Nonnull
IOperationUntypedWithInput buildTranslate(@Nonnull UriType url,
@Nonnull UriType system,
@Nullable StringType version, @Nonnull CodeType code, @Nullable BooleanType reverse,
@Nullable UriType target);
/**
* @param codeA the code that will be tested to check if it subsumes codeB
* @param codeB the code that will be tested to check if it is subsumed by codeA
* @param system the system of the codes being tested
* @param version the version of the code system that the codes are from
* @return a {@link Parameters} resource
* @see CodeSystem/$subsumes
*/
@Operation(name = "$subsumes", type = CodeSystem.class, idempotent = true)
@Nonnull
Parameters subsumes(
@Nonnull @OperationParam(name = "codeA") CodeType codeA,
@Nonnull @OperationParam(name = "codeB") CodeType codeB,
@Nonnull @OperationParam(name = "system") UriType system,
@Nullable @OperationParam(name = "version") StringType version
);
/**
* Builds a subsumes operation that can be customized and executed later.
*
* @param codeA the code that will be tested to check if it subsumes codeB
* @param codeB the code that will be tested to check if it is subsumed by codeA
* @param system the system of the codes being tested
* @param version the version of the code system that the codes are from
* @return an {@link IOperationUntypedWithInput} that can be customized and executed later
* @see CodeSystem/$subsumes
*/
@Nonnull
IOperationUntypedWithInput buildSubsumes(@Nonnull CodeType codeA,
@Nonnull CodeType codeB, @Nonnull UriType system, @Nullable StringType version);
/**
* @param system the system of the code
* @param version the version of the code system
* @param code the code to lookup
* @param property the property or properties to be returned in the response
* @return a {@link Parameters} resource
* @see CodeSystem/$lookup
*/
@Operation(name = "$lookup", type = CodeSystem.class, idempotent = true)
@Nonnull
Parameters lookup(
@Nonnull @OperationParam(name = "system") UriType system,
@Nullable @OperationParam(name = "version") StringType version,
@Nonnull @OperationParam(name = "code") CodeType code,
@Nullable @OperationParam(name = "property") CodeType property
);
/**
* Builds a lookup operation that can be customized and executed later.
*
* @param system the system of the code
* @param version the version of the code system
* @param code the code to lookup
* @param property the property or properties to be returned in the response
* @return an {@link IOperationUntypedWithInput} that can be customized and executed later
* @see CodeSystem/$lookup
*/
@Nonnull
IOperationUntypedWithInput buildLookup(@Nonnull UriType system,
@Nullable StringType version, @Nonnull CodeType code, @Nullable CodeType property);
/**
* Builds a new terminology client.
*
* @param fhirContext the FHIR context to use for building the client
* @param terminologyConfiguration a {@link TerminologyConfiguration} to govern the behaviour of
* the client
* @param httpClient the {@link HttpClient} instance to use for making HTTP requests
* @return the new instance of {@link TerminologyClient}
*/
static TerminologyClient build(@Nonnull final FhirContext fhirContext,
@Nonnull final TerminologyConfiguration terminologyConfiguration,
@Nonnull final HttpClient httpClient) {
final IRestfulClientFactory restfulClientFactory = fhirContext.getRestfulClientFactory();
restfulClientFactory.setHttpClient(httpClient);
restfulClientFactory.setServerValidationMode(ServerValidationModeEnum.NEVER);
final IGenericClient genericClient = restfulClientFactory.newGenericClient(
terminologyConfiguration.getServerUrl());
// Register an interceptor that identifies the Pathling client within the request headers.
genericClient.registerInterceptor(new UserAgentInterceptor());
// If verbose logging is enabled, register an interceptor that logs the request and response
// details.
if (terminologyConfiguration.isVerboseLogging()) {
final LoggingInterceptor verboseLogging = buildVerboseLogging();
genericClient.registerInterceptor(verboseLogging);
}
// If authentication is enabled, register an interceptor that authenticates requests before
// sending them.
final TerminologyAuthConfiguration authConfig = terminologyConfiguration.getAuthentication();
if (authConfig.isEnabled()) {
genericClient.registerInterceptor(new ClientAuthInterceptor(authConfig));
}
return new DefaultTerminologyClient(genericClient);
}
@Nonnull
private static LoggingInterceptor buildVerboseLogging() {
final LoggingInterceptor loggingInterceptor = new LoggingInterceptor();
loggingInterceptor.setLogger(log);
loggingInterceptor.setLogRequestSummary(true);
loggingInterceptor.setLogResponseSummary(true);
loggingInterceptor.setLogRequestHeaders(true);
loggingInterceptor.setLogResponseHeaders(true);
loggingInterceptor.setLogRequestBody(true);
loggingInterceptor.setLogResponseBody(true);
return loggingInterceptor;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy