- add TLS support for JaxRsClient and OkHttpClient

- add tests
This commit is contained in:
nathaniel.doef 2022-07-07 21:47:12 -04:00
parent 5388f729fb
commit 25d8a0f5e1
31 changed files with 1263 additions and 714 deletions

View File

@ -911,6 +911,7 @@ public class FhirContext {
* </p>
*
* @param theServerBase The URL of the base for the restful FHIR server to connect to
* @param theTlsAuthentication Optional configuration to authenticate HTTPS server requests
*/
public IGenericClient newRestfulGenericClient(final String theServerBase, final Optional<TlsAuthentication> theTlsAuthentication) {
return getRestfulClientFactory().newGenericClient(theServerBase, theTlsAuthentication);

View File

@ -94,6 +94,24 @@ public interface IRestfulClientFactory {
*/
IHttpClient getHttpClient(StringBuilder theUrl, Map<String, List<String>> theIfNoneExistParams, String theIfNoneExistString, RequestTypeEnum theRequestType, List<Header> theHeaders);
/**
* Returns the HTTP client instance. This method will not return null.
* @param theUrl
* The complete FHIR url to which the http request will be sent
* @param theTlsAuthentication
* Optional configuration to authenticate HTTPS server requests
* @param theIfNoneExistParams
* The params for header "If-None-Exist" as a hashmap
* @param theIfNoneExistString
* The param for header "If-None-Exist" as a string
* @param theRequestType
* the type of HTTP request (GET, DELETE, ..)
* @param theHeaders
* the headers to be sent together with the http request
* @return the HTTP client instance
*/
IHttpClient getHttpClient(StringBuilder theUrl, Optional<TlsAuthentication> theTlsAuthentication, Map<String, List<String>> theIfNoneExistParams, String theIfNoneExistString, RequestTypeEnum theRequestType, List<Header> theHeaders);
/**
* @deprecated Use {@link #getServerValidationMode()} instead (this method is a synonym for that method, but this method is poorly named and will be removed at some point)
*/
@ -164,6 +182,8 @@ public interface IRestfulClientFactory {
*
* @param theServerBase
* The URL of the base for the restful FHIR server to connect to
* @param
* theTlsAuthentication Optional configuration to authenticate HTTPS server requests
* @return A newly created client
*/
IGenericClient newGenericClient(String theServerBase, Optional<TlsAuthentication> theTlsAuthentication);

View File

@ -1,7 +1,6 @@
package ca.uhn.fhir.rest.https;
import org.apache.commons.io.FilenameUtils;
import org.apache.http.ssl.PrivateKeyStrategy;
import static org.apache.commons.lang3.StringUtils.isBlank;
@ -18,6 +17,7 @@ public class KeyStoreInfo {
myStorePass = toCharArrayOrNull(theStorePass);
myKeyPass = toCharArrayOrNull(theKeyPass);
myAlias = theAlias;
String extension = FilenameUtils.getExtension(myFilePath);
myType = KeyStoreType.fromFileExtension(extension);
}
@ -39,8 +39,7 @@ public class KeyStoreInfo {
}
public KeyStoreType getType(){
String extension = FilenameUtils.getExtension(myFilePath);
return KeyStoreType.fromFileExtension(extension);
return myType;
}
private char[] toCharArrayOrNull(String theString){

View File

@ -0,0 +1,82 @@
package ca.uhn.fhir.rest.https;
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.ssl.PrivateKeyStrategy;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.SSLContexts;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.util.Optional;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class TlsAuthenticationSvc {
private TlsAuthenticationSvc(){}
public static Optional<SSLContext> createSslContext(Optional<TlsAuthentication> theTlsAuthentication){
if(theTlsAuthentication.isEmpty()){
return Optional.empty();
}
try{
SSLContextBuilder contextBuilder = SSLContexts.custom();
TlsAuthentication tlsAuth = theTlsAuthentication.get();
if(tlsAuth.getKeyStoreInfo().isPresent()){
KeyStoreInfo keyStoreInfo = tlsAuth.getKeyStoreInfo().get();
PrivateKeyStrategy privateKeyStrategy = null;
if(isNotBlank(keyStoreInfo.getAlias())){
privateKeyStrategy = (aliases, socket) -> keyStoreInfo.getAlias();
}
contextBuilder.loadKeyMaterial(new File(keyStoreInfo.getFilePath()), keyStoreInfo.getStorePass(), keyStoreInfo.getKeyPass(), privateKeyStrategy);
}
if(tlsAuth.getTrustStoreInfo().isPresent()){
TrustStoreInfo trustStoreInfo = tlsAuth.getTrustStoreInfo().get();
contextBuilder.loadTrustMaterial(new File(trustStoreInfo.getFilePath()), trustStoreInfo.getStorePass(), TrustSelfSignedStrategy.INSTANCE);
}
return Optional.of(contextBuilder.build());
}
catch (Exception e){
throw new RuntimeException(e);
}
}
public static X509TrustManager createTrustManager(Optional<TrustStoreInfo> theTrustStoreInfo) {
try {
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
if (theTrustStoreInfo.isEmpty()) {
trustManagerFactory.init((KeyStore) null); // Load Trust Manager Factory with default Java truststore
} else {
TrustStoreInfo trustStoreInfo = theTrustStoreInfo.get();
KeyStore trustStore = KeyStore.getInstance(trustStoreInfo.getType().toString());
trustStore.load(new FileInputStream(trustStoreInfo.getFilePath()), trustStoreInfo.getStorePass());
trustManagerFactory.init(trustStore);
}
for (TrustManager trustManager : trustManagerFactory.getTrustManagers()) {
if (trustManager instanceof X509TrustManager) {
return (X509TrustManager) trustManager;
}
}
throw new RuntimeException("Could not find Trust Manager");
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
public static HostnameVerifier createHostnameVerifier(Optional<TrustStoreInfo> theTrustStoreInfo){
return theTrustStoreInfo.isPresent() ? new DefaultHostnameVerifier() : new NoopHostnameVerifier();
}
}

View File

@ -9,10 +9,13 @@ public class TrustStoreInfo {
private final String myFilePath;
private final char[] myStorePass;
private final KeyStoreType myType;
private final String myAlias;
public TrustStoreInfo(String theFilePath, String theStorePass) {
public TrustStoreInfo(String theFilePath, String theStorePass, String theAlias) {
myFilePath = theFilePath;
myStorePass = toCharArrayOrNull(theStorePass);
myAlias = theAlias;
String extension = FilenameUtils.getExtension(myFilePath);
myType = KeyStoreType.fromFileExtension(extension);
}
@ -26,11 +29,14 @@ public class TrustStoreInfo {
}
public KeyStoreType getType(){
String extension = FilenameUtils.getExtension(myFilePath);
return KeyStoreType.fromFileExtension(extension);
return myType;
}
private char[] toCharArrayOrNull(String theString){
return isBlank(theString) ? null : theString.toCharArray();
}
public String getAlias() {
return myAlias;
}
}

View File

@ -89,7 +89,7 @@ public abstract class BaseCommand implements Comparable<BaseCommand> {
protected static final String BASE_URL_PARAM_DESC = "Base URL for the target server (e.g. \"http://example.com/fhir\").";
protected static final String TLS_AUTH_PARAM_LONGOPT = "tls-auth";
protected static final String TLS_AUTH_PARAM_NAME = "tls-auth";
protected static final String TLS_AUTH_PARAM_DESC = "If specified, this parameter supplies a path and filename for a json authentication file that will be used to authenticate https requests.";
protected static final String TLS_AUTH_PARAM_DESC = "If specified, this parameter supplies a path and filename for a json authentication file that will be used to authenticate HTTPS requests.";
protected static final String BASIC_AUTH_PARAM = "b";
protected static final String BASIC_AUTH_PARAM_LONGOPT = "basic-auth";
protected static final String BASIC_AUTH_PARAM_NAME = "basic-auth";
@ -475,7 +475,7 @@ public abstract class BaseCommand implements Comparable<BaseCommand> {
}
protected IGenericClient newClient(CommandLine theCommandLine, String theBaseUrlParamName, String theBasicAuthOptionName,
String theBearerTokenOptionName, String theHttpsAuthOptionName) throws ParseException {
String theBearerTokenOptionName, String theTlsAuthOptionName) throws ParseException {
String baseUrl = theCommandLine.getOptionValue(theBaseUrlParamName);
if (isBlank(baseUrl)) {
throw new ParseException(Msg.code(1579) + "No target server (-" + BASE_URL_PARAM + ") specified.");
@ -483,15 +483,15 @@ public abstract class BaseCommand implements Comparable<BaseCommand> {
throw new ParseException(Msg.code(1580) + "Invalid target server specified, must begin with 'http' or 'file'.");
}
return newClientWithBaseUrl(theCommandLine, baseUrl, theBasicAuthOptionName, theBearerTokenOptionName, theHttpsAuthOptionName);
return newClientWithBaseUrl(theCommandLine, baseUrl, theBasicAuthOptionName, theBearerTokenOptionName, theTlsAuthOptionName);
}
protected IGenericClient newClientWithBaseUrl(CommandLine theCommandLine, String theBaseUrl, String theBasicAuthOptionName,
String theBearerTokenOptionName, String theHttpsAuthOptionName) throws ParseException {
String theBearerTokenOptionName, String theTlsAuthOptionName) throws ParseException {
myFhirCtx.getRestfulClientFactory().setSocketTimeout((int) DateUtils.MILLIS_PER_HOUR);
Optional<TlsAuthentication> tlsConfig = createTlsConfig(theCommandLine, theHttpsAuthOptionName);
Optional<TlsAuthentication> tlsConfig = createTlsConfig(theCommandLine, theTlsAuthOptionName);
IGenericClient retVal = myFhirCtx.newRestfulGenericClient(theBaseUrl, tlsConfig);
String basicAuthHeaderValue = getAndParseOptionBasicAuthHeader(theCommandLine, theBasicAuthOptionName);
@ -509,8 +509,8 @@ public abstract class BaseCommand implements Comparable<BaseCommand> {
return retVal;
}
private Optional<TlsAuthentication> createTlsConfig(CommandLine theCommandLine, String theHttpsAuthOptionName){
String httpAuthFilePath = theCommandLine.getOptionValue(theHttpsAuthOptionName);
private Optional<TlsAuthentication> createTlsConfig(CommandLine theCommandLine, String theTlsAuthOptionName){
String httpAuthFilePath = theCommandLine.getOptionValue(theTlsAuthOptionName);
if(isBlank(httpAuthFilePath)){
return Optional.empty();
}
@ -529,28 +529,39 @@ public abstract class BaseCommand implements Comparable<BaseCommand> {
}
}
private Optional<KeyStoreInfo> createKeyStoreInfo(JsonObject theJson){
private Optional<KeyStoreInfo> createKeyStoreInfo(JsonObject theJson) throws ParseException {
String filePath = theJson.get("filePath").getAsString();
if(isBlank(filePath)){
return Optional.empty();
}
String storePass = theJson.get("storePass").getAsString();
if (PROMPT.equals(storePass)) {
storePass = trim(promptUser("Enter the store password for the keystore: "));
}
String keyPass = theJson.get("keyPass").getAsString();
if (PROMPT.equals(keyPass)) {
keyPass = trim(promptUser("Enter the key password for the keystore: "));
}
String alias = theJson.get("alias").getAsString();
KeyStoreInfo keyStoreInfo = new KeyStoreInfo(filePath, storePass, keyPass, alias);
return Optional.of(keyStoreInfo);
}
private Optional<TrustStoreInfo> createTrustStoreInfo(JsonObject theJson){
private Optional<TrustStoreInfo> createTrustStoreInfo(JsonObject theJson) throws ParseException {
String filePath = theJson.get("filePath").getAsString();
if(isBlank(filePath)){
return Optional.empty();
}
String storePass = theJson.get("storePass").getAsString();
TrustStoreInfo trustStoreInfo = new TrustStoreInfo(filePath, storePass);
if (PROMPT.equals(storePass)) {
storePass = trim(promptUser("Enter the store password for the truststore: "));
}
String alias = theJson.get("alias").getAsString();
TrustStoreInfo trustStoreInfo = new TrustStoreInfo(filePath, storePass, alias);
return Optional.of(trustStoreInfo);
}

View File

@ -94,9 +94,10 @@ public abstract class BaseRequestGeneratingCommand extends BaseCommand {
@Override
protected IGenericClient newClientWithBaseUrl(CommandLine theCommandLine, String theBaseUrl,
String theBasicAuthOptionName, String theBearerTokenOptionName, String theHttpsAuthOptionName) throws ParseException {
String theBasicAuthOptionName, String theBearerTokenOptionName, String theTlsAuthOptionName) throws ParseException {
IGenericClient client = super.newClientWithBaseUrl(theCommandLine, theBaseUrl, theBasicAuthOptionName, theBearerTokenOptionName, theHttpsAuthOptionName);
IGenericClient client = super.newClientWithBaseUrl(
theCommandLine, theBaseUrl, theBasicAuthOptionName, theBearerTokenOptionName, theTlsAuthOptionName);
registerHeaderPassthrough(theCommandLine, client);
return client;

View File

@ -46,6 +46,7 @@ import java.util.concurrent.ExecutionException;
import static org.apache.commons.lang3.StringUtils.defaultString;
public class ExportConceptMapToCsvCommand extends AbstractImportExportCsvConceptMapCommand {
public static final String COMMAND = "export-conceptmap-to-csv";
// TODO: Don't use qualified names for loggers in HAPI CLI.
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExportConceptMapToCsvCommand.class);

View File

@ -51,6 +51,8 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class ImportCsvToConceptMapCommand extends AbstractImportExportCsvConceptMapCommand {
public static final String COMMAND = "import-csv-to-conceptmap";
// TODO: Don't use qualified names for loggers in HAPI CLI.
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ImportCsvToConceptMapCommand.class);
@ -58,22 +60,11 @@ public class ImportCsvToConceptMapCommand extends AbstractImportExportCsvConcept
protected static final String SOURCE_VALUE_SET_PARAM_LONGOPT = "input";
protected static final String SOURCE_VALUE_SET_PARAM_NAME = "input";
protected static final String SOURCE_VALUE_SET_PARAM_DESC = "The source value set of the ConceptMap to be imported (i.e. ConceptMap.sourceUri).";
protected static final String TARGET_VALUE_SET_PARAM = "o";
protected static final String TARGET_VALUE_SET_PARAM_LONGOPT = "output";
protected static final String TARGET_VALUE_SET_PARAM_NAME = "output";
protected static final String TARGET_VALUE_SET_PARAM_DESC = "The target value set of the ConceptMap to be imported (i.e. ConceptMap.targetUri).";
protected static final String CLIENT_CERTIFICATION_PARAM = "c";
protected static final String CLIENT_CERTIFICATION_PARAM_LONGOPT = "cert";
protected static final String CLIENT_CERTIFICATION_PARAM_NAME = "cert";
protected static final String CLIENT_CERTIFICATION_PARAM_DESC = "The client certification to be used for TLS";
protected static final String CLIENT_KEY_PARAM = "k";
protected static final String CLIENT_KEY_PARAM_LONGOPT = "key";
protected static final String CLIENT_KEY_PARAM_NAME = "key";
protected static final String CLIENT_KEY_PARAM_DESC = "The client key to be used for TLS";
protected String sourceValueSet;
protected String targetValueSet;
@ -98,9 +89,6 @@ public class ImportCsvToConceptMapCommand extends AbstractImportExportCsvConcept
// </editor-fold desc="Additional parameters.">
addOptionalOption(options, SOURCE_VALUE_SET_PARAM, SOURCE_VALUE_SET_PARAM_LONGOPT, SOURCE_VALUE_SET_PARAM_NAME, SOURCE_VALUE_SET_PARAM_DESC);
addOptionalOption(options, TARGET_VALUE_SET_PARAM, TARGET_VALUE_SET_PARAM_LONGOPT, TARGET_VALUE_SET_PARAM_NAME, TARGET_VALUE_SET_PARAM_DESC);
addOptionalOption(options, CLIENT_CERTIFICATION_PARAM, CLIENT_CERTIFICATION_PARAM_LONGOPT, CLIENT_CERTIFICATION_PARAM_NAME, CLIENT_CERTIFICATION_PARAM_DESC);
addOptionalOption(options, CLIENT_KEY_PARAM, CLIENT_KEY_PARAM_LONGOPT, CLIENT_KEY_PARAM_NAME, CLIENT_KEY_PARAM_DESC);
// </editor-fold>
addRequiredOption(options, FILE_PARAM, FILE_PARAM_LONGOPT, FILE_PARAM_NAME, FILE_PARAM_DESC);

View File

@ -46,7 +46,6 @@ public class ToggleSearchParametersCommand extends BaseCommand {
addBaseUrlOption(options);
addRequiredOption(options, "u", "url", true, "The code system URL associated with this upload (e.g. " + ITermLoaderSvc.SCT_URI + ")");
addBasicAuthOption(options);
addHttpsAuthOption(options);
return options;
}

View File

@ -1,15 +1,19 @@
package ca.uhn.fhir.cli;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.client.interceptor.CapturingInterceptor;
import ca.uhn.fhir.test.utilities.server.RestfulServerExtension;
import ca.uhn.fhir.test.utilities.BaseRequestGeneratingCommandTestUtil;
import ca.uhn.fhir.test.utilities.RestServerR4Helper;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.ParseException;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.Resource;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import java.io.File;
import java.util.List;
@ -24,10 +28,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
class ExampleDataUploaderTest {
private FhirContext myCtx = FhirContext.forR4();
@RegisterExtension
public final RestfulServerExtension myRestfulServerExtension = new RestfulServerExtension(myCtx);
public final RestServerR4Helper myRestServerR4Helper = new RestServerR4Helper();
@RegisterExtension
public BaseRequestGeneratingCommandTestUtil myBaseRequestGeneratingCommandTestUtil = new BaseRequestGeneratingCommandTestUtil();
private final CapturingInterceptor myCapturingInterceptor = new CapturingInterceptor();
private final ExampleDataUploader testedCommand = new RequestCapturingExampleDataUploader(myCapturingInterceptor);
@ -40,19 +44,20 @@ class ExampleDataUploaderTest {
inputFilePath = resourcesPath + "/sample.json.zip";
}
@Test
public void testHeaderPassthrough() throws ParseException {
@ParameterizedTest
@ValueSource(booleans = {true, false})
public void testHeaderPassthrough(boolean theIncludeTls) throws ParseException {
String headerKey = "test-header-key";
String headerValue = "test header value";
String[] args = new String[] {
"-v", "r4", // BaseRequestGeneratingCommandTest required
"-t", "http://localhost:8000", // BaseRequestGeneratingCommandTest required
"-d", inputFilePath,
"-hp", headerKey + ":" + headerValue // optional
};
String[] args = myBaseRequestGeneratingCommandTestUtil.createArgs(
new String[]{
"-v", "r4", // BaseRequestGeneratingCommandTest required
"-d", inputFilePath,
"-hp", headerKey + ":" + headerValue // optional
},
"-t", theIncludeTls, myRestServerR4Helper // BaseRequestGeneratingCommandTest required
);
final CommandLine commandLine = new DefaultParser().parse(testedCommand.getOptions(), args, true);
testedCommand.run(commandLine);
@ -65,8 +70,13 @@ class ExampleDataUploaderTest {
assertEquals(1, allHeaders.get(headerKey).size());
assertThat(allHeaders.get(headerKey), hasItems(headerValue));
}
assertEquals(1, myRestServerR4Helper.getTransactions().size());
Bundle bundle = myRestServerR4Helper.getTransactions().get(0);
Resource resource = bundle.getEntry().get(0).getResource();
assertEquals(Patient.class, resource.getClass());
assertEquals("EX3152", resource.getIdElement().getIdPart());
}
private static class RequestCapturingExampleDataUploader extends ExampleDataUploader {
private final CapturingInterceptor myCapturingInterceptor;

View File

@ -1,25 +1,21 @@
package ca.uhn.fhir.cli;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.interceptor.VerboseLoggingInterceptor;
import ca.uhn.fhir.test.utilities.JettyUtil;
import ca.uhn.fhir.test.utilities.LoggingExtension;
import ca.uhn.fhir.test.utilities.BaseRequestGeneratingCommandTestUtil;
import ca.uhn.fhir.test.utilities.RestServerDstu3Helper;
import ca.uhn.fhir.util.TestUtil;
import com.google.common.base.Charsets;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.hl7.fhir.dstu3.model.ConceptMap;
import org.hl7.fhir.dstu3.model.Enumerations.ConceptMapEquivalence;
import org.hl7.fhir.dstu3.model.UriType;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import java.io.File;
import java.io.FileInputStream;
@ -38,30 +34,50 @@ public class ExportConceptMapToCsvCommandDstu3Test {
private static final String CS_URL_3 = "http://example.com/codesystem/3";
private static final String FILE = "./target/output_dstu3.csv";
private static String ourBase;
private static IGenericClient ourClient;
private static FhirContext ourCtx = FhirContext.forDstu3();
private static int ourPort;
private static Server ourServer;
private static String ourVersion = "dstu3";
private final FhirContext myCtx = FhirContext.forDstu3();
private final String myVersion = "dstu3";
static {
System.setProperty("test", "true");
}
@RegisterExtension
public LoggingExtension myLoggingExtension = new LoggingExtension();
public final RestServerDstu3Helper myRestServerDstu3Helper = new RestServerDstu3Helper(true);
@RegisterExtension
public BaseRequestGeneratingCommandTestUtil myBaseRequestGeneratingCommandTestUtil = new BaseRequestGeneratingCommandTestUtil();
@Test
public void testExportConceptMapToCsvCommand() throws IOException {
ourLog.debug("ConceptMap:\n" + ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(createConceptMap()));
@BeforeEach
public void before(){
myRestServerDstu3Helper.setConceptMapResourceProvider(new HashMapResourceProviderConceptMapDstu3(myCtx));
myRestServerDstu3Helper.getClient().create().resource(createConceptMap()).execute();
}
@AfterEach
public void afterEach() {
myRestServerDstu3Helper.clearDataAndCounts();
}
@AfterAll
public static void afterAll(){
TestUtil.randomizeLocaleAndTimezone();
}
@ParameterizedTest
@ValueSource(booleans = {true, false})
public void testExportConceptMapToCsvCommandNoTls(boolean theIncludeTls) throws IOException {
ourLog.debug("ConceptMap:\n" + myCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(createConceptMap()));
App.main(myBaseRequestGeneratingCommandTestUtil.createArgs(
new String[]{
ExportConceptMapToCsvCommand.COMMAND,
"-v", myVersion,
"-u", CM_URL,
"-f", FILE,
"-l"
},
"-t", theIncludeTls, myRestServerDstu3Helper
));
App.main(new String[]{"export-conceptmap-to-csv",
"-v", ourVersion,
"-t", ourBase,
"-u", CM_URL,
"-f", FILE,
"-l"});
await().until(() -> new File(FILE).exists());
String expected = "\"SOURCE_CODE_SYSTEM\",\"SOURCE_CODE_SYSTEM_VERSION\",\"TARGET_CODE_SYSTEM\",\"TARGET_CODE_SYSTEM_VERSION\",\"SOURCE_CODE\",\"SOURCE_DISPLAY\",\"TARGET_CODE\",\"TARGET_DISPLAY\",\"EQUIVALENCE\",\"COMMENT\"\n" +
@ -85,36 +101,6 @@ public class ExportConceptMapToCsvCommandDstu3Test {
FileUtils.deleteQuietly(new File(FILE));
}
@AfterAll
public static void afterClassClearContext() throws Exception {
JettyUtil.closeServer(ourServer);
TestUtil.randomizeLocaleAndTimezone();
}
@BeforeAll
public static void beforeClass() throws Exception {
ourServer = new Server(0);
ServletHandler servletHandler = new ServletHandler();
RestfulServer restfulServer = new RestfulServer(ourCtx);
restfulServer.registerInterceptor(new VerboseLoggingInterceptor());
restfulServer.setResourceProviders(new HashMapResourceProviderConceptMapDstu3(ourCtx));
ServletHolder servletHolder = new ServletHolder(restfulServer);
servletHandler.addServletWithMapping(servletHolder, "/*");
ourServer.setHandler(servletHandler);
JettyUtil.startServer(ourServer);
ourPort = JettyUtil.getPortForStartedServer(ourServer);
ourBase = "http://localhost:" + ourPort;
ourClient = ourCtx.newRestfulGenericClient(ourBase);
ourClient.create().resource(createConceptMap()).execute();
}
static ConceptMap createConceptMap() {
ConceptMap conceptMap = new ConceptMap();
conceptMap

View File

@ -1,23 +1,21 @@
package ca.uhn.fhir.cli;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.interceptor.VerboseLoggingInterceptor;
import ca.uhn.fhir.test.utilities.JettyUtil;
import ca.uhn.fhir.test.utilities.BaseRequestGeneratingCommandTestUtil;
import ca.uhn.fhir.test.utilities.RestServerR4Helper;
import ca.uhn.fhir.util.TestUtil;
import com.google.common.base.Charsets;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.Enumerations.ConceptMapEquivalence;
import org.hl7.fhir.r4.model.UriType;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import java.io.File;
import java.io.FileInputStream;
@ -36,27 +34,50 @@ public class ExportConceptMapToCsvCommandR4Test {
private static final String CS_URL_3 = "http://example.com/codesystem/3";
private static final String FILE = new File("./target/output_r4.csv").getAbsolutePath();
private static String ourBase;
private static IGenericClient ourClient;
private static FhirContext ourCtx = FhirContext.forR4();
private static int ourPort;
private static Server ourServer;
private static String ourVersion = "r4";
static {
System.setProperty("test", "true");
}
@Test
public void testExportConceptMapToCsvCommand() throws IOException {
ourLog.info("ConceptMap:\n" + ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(createConceptMap()));
@RegisterExtension
public final RestServerR4Helper myRestServerR4Helper = new RestServerR4Helper(true);
@RegisterExtension
public BaseRequestGeneratingCommandTestUtil myBaseRequestGeneratingCommandTestUtil = new BaseRequestGeneratingCommandTestUtil();
private final FhirContext myCtx = FhirContext.forR4();
private final String myVersion = "r4";
@BeforeEach
public void before(){
myRestServerR4Helper.setConceptMapResourceProvider(new HashMapResourceProviderConceptMapR4(myCtx));
myRestServerR4Helper.getClient().create().resource(createConceptMap()).execute();
}
@AfterEach
public void afterEach() {
myRestServerR4Helper.clearDataAndCounts();
}
@AfterAll
public static void afterAll(){
TestUtil.randomizeLocaleAndTimezone();
}
@ParameterizedTest
@ValueSource(booleans = {true, false})
public void testExportConceptMapToCsvCommand(boolean theIncludeTls) throws IOException {
ourLog.info("ConceptMap:\n" + myCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(createConceptMap()));
App.main(myBaseRequestGeneratingCommandTestUtil.createArgs(
new String[]{
ExportConceptMapToCsvCommand.COMMAND,
"-v", myVersion,
"-u", CM_URL,
"-f", FILE,
"-l"
},
"-t", theIncludeTls, myRestServerR4Helper
));
App.main(new String[]{"export-conceptmap-to-csv",
"-v", ourVersion,
"-t", ourBase,
"-u", CM_URL,
"-f", FILE,
"-l"});
await().until(() -> new File(FILE).exists());
String expected = "\"SOURCE_CODE_SYSTEM\",\"SOURCE_CODE_SYSTEM_VERSION\",\"TARGET_CODE_SYSTEM\",\"TARGET_CODE_SYSTEM_VERSION\",\"SOURCE_CODE\",\"SOURCE_DISPLAY\",\"TARGET_CODE\",\"TARGET_DISPLAY\",\"EQUIVALENCE\",\"COMMENT\"\n" +
@ -78,36 +99,6 @@ public class ExportConceptMapToCsvCommandR4Test {
FileUtils.deleteQuietly(new File(FILE));
}
@AfterAll
public static void afterClassClearContext() throws Exception {
JettyUtil.closeServer(ourServer);
TestUtil.randomizeLocaleAndTimezone();
}
@BeforeAll
public static void beforeClass() throws Exception {
ourServer = new Server(0);
ServletHandler servletHandler = new ServletHandler();
RestfulServer restfulServer = new RestfulServer(ourCtx);
restfulServer.registerInterceptor(new VerboseLoggingInterceptor());
restfulServer.setResourceProviders(new HashMapResourceProviderConceptMapR4(ourCtx));
ServletHolder servletHolder = new ServletHolder(restfulServer);
servletHandler.addServletWithMapping(servletHolder, "/*");
ourServer.setHandler(servletHandler);
JettyUtil.startServer(ourServer);
ourPort = JettyUtil.getPortForStartedServer(ourServer);
ourBase = "http://localhost:" + ourPort;
ourClient = ourCtx.newRestfulGenericClient(ourBase);
ourClient.create().resource(createConceptMap()).execute();
}
static ConceptMap createConceptMap() {
ConceptMap conceptMap = new ConceptMap();
conceptMap

View File

@ -2,14 +2,9 @@ package ca.uhn.fhir.cli;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.interceptor.VerboseLoggingInterceptor;
import ca.uhn.fhir.test.utilities.JettyUtil;
import ca.uhn.fhir.test.utilities.BaseRequestGeneratingCommandTestUtil;
import ca.uhn.fhir.test.utilities.RestServerDstu3Helper;
import ca.uhn.fhir.util.TestUtil;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.ConceptMap;
import org.hl7.fhir.dstu3.model.ConceptMap.ConceptMapGroupComponent;
@ -19,8 +14,11 @@ import org.hl7.fhir.dstu3.model.Enumerations.ConceptMapEquivalence;
import org.hl7.fhir.exceptions.FHIRException;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import java.io.File;
@ -37,26 +35,32 @@ public class ImportCsvToConceptMapCommandDstu3Test {
private static final String CS_URL_3 = "http://example.com/codesystem/3";
private static final String FILENAME = "import-csv-to-conceptmap-command-test-input.csv";
private static String file;
private static String ourBase;
private static IGenericClient ourClient;
private static FhirContext ourCtx = FhirContext.forDstu3();
private static int ourPort;
private static Server ourServer;
private static String ourVersion = "dstu3";
private static RestfulServer restfulServer;
private static HashMapResourceProviderConceptMapDstu3 hashMapResourceProviderConceptMapDstu3;
private final FhirContext myCtx = FhirContext.forDstu3();
private final String myVersion = "dstu3";
private String myFile;
static {
System.setProperty("test", "true");
}
@RegisterExtension
public final RestServerDstu3Helper myRestServerDstu3Helper = new RestServerDstu3Helper(true);
@RegisterExtension
public BaseRequestGeneratingCommandTestUtil myBaseRequestGeneratingCommandTestUtil = new BaseRequestGeneratingCommandTestUtil();
@BeforeEach
public void before(){
myRestServerDstu3Helper.setConceptMapResourceProvider(new HashMapResourceProviderConceptMapDstu3(myCtx));
}
@AfterEach
public void afterClearResourceProvider() {
HashMapResourceProviderConceptMapDstu3 resourceProvider = (HashMapResourceProviderConceptMapDstu3) restfulServer.getResourceProviders().iterator().next();
resourceProvider.clear();
public void afterEach() {
myRestServerDstu3Helper.clearDataAndCounts();
}
@AfterAll
public static void afterAll(){
TestUtil.randomizeLocaleAndTimezone();
}
@Test
@ -65,7 +69,7 @@ public class ImportCsvToConceptMapCommandDstu3Test {
String conceptMapUrl = conceptMap.getUrl();
ourLog.info("Searching for existing ConceptMap with specified URL (i.e. ConceptMap.url): {}", conceptMapUrl);
MethodOutcome methodOutcome = ourClient
MethodOutcome methodOutcome = myRestServerDstu3Helper.getClient()
.update()
.resource(conceptMap)
.conditional()
@ -78,11 +82,11 @@ public class ImportCsvToConceptMapCommandDstu3Test {
@Test
public void testConditionalUpdateResultsInUpdate() {
ConceptMap conceptMap = ExportConceptMapToCsvCommandDstu3Test.createConceptMap();
ourClient.create().resource(conceptMap).execute();
myRestServerDstu3Helper.getClient().create().resource(conceptMap).execute();
String conceptMapUrl = conceptMap.getUrl();
ourLog.info("Searching for existing ConceptMap with specified URL (i.e. ConceptMap.url): {}", conceptMapUrl);
MethodOutcome methodOutcome = ourClient
MethodOutcome methodOutcome = myRestServerDstu3Helper.getClient()
.update()
.resource(conceptMap)
.conditional()
@ -95,9 +99,9 @@ public class ImportCsvToConceptMapCommandDstu3Test {
@Test
public void testNonConditionalUpdate() {
ConceptMap conceptMap = ExportConceptMapToCsvCommandDstu3Test.createConceptMap();
ourClient.create().resource(conceptMap).execute();
myRestServerDstu3Helper.getClient().create().resource(conceptMap).execute();
Bundle response = ourClient
Bundle response = myRestServerDstu3Helper.getClient()
.search()
.forResource(ConceptMap.class)
.where(ConceptMap.URL.matches().value(CM_URL))
@ -106,7 +110,7 @@ public class ImportCsvToConceptMapCommandDstu3Test {
ConceptMap resultConceptMap = (ConceptMap) response.getEntryFirstRep().getResource();
MethodOutcome methodOutcome = ourClient
MethodOutcome methodOutcome = myRestServerDstu3Helper.getClient()
.update()
.resource(resultConceptMap)
.withId(resultConceptMap.getIdElement())
@ -115,22 +119,27 @@ public class ImportCsvToConceptMapCommandDstu3Test {
assertNull(methodOutcome.getCreated());
}
@Test
public void testImportCsvToConceptMapCommand() throws FHIRException {
@ParameterizedTest
@ValueSource(booleans = {true, false})
public void testImportCsvToConceptMapCommandNoTls(boolean theIncludeTls) throws FHIRException {
ClassLoader classLoader = getClass().getClassLoader();
File fileToImport = new File(classLoader.getResource(FILENAME).getFile());
ImportCsvToConceptMapCommandDstu3Test.file = fileToImport.getAbsolutePath();
myFile = fileToImport.getAbsolutePath();
App.main(new String[]{"import-csv-to-conceptmap",
"-v", ourVersion,
"-t", ourBase,
"-u", CM_URL,
"-i", VS_URL_1,
"-o", VS_URL_2,
"-f", file,
"-l"});
App.main(myBaseRequestGeneratingCommandTestUtil.createArgs(
new String[]{
ImportCsvToConceptMapCommand.COMMAND,
"-v", myVersion,
"-u", CM_URL,
"-i", VS_URL_1,
"-o", VS_URL_2,
"-f", myFile,
"-l"
},
"-t", theIncludeTls, myRestServerDstu3Helper
));
Bundle response = ourClient
Bundle response = myRestServerDstu3Helper.getClient()
.search()
.forResource(ConceptMap.class)
.where(ConceptMap.URL.matches().value(CM_URL))
@ -139,9 +148,9 @@ public class ImportCsvToConceptMapCommandDstu3Test {
ConceptMap conceptMap = (ConceptMap) response.getEntryFirstRep().getResource();
ourLog.info(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
ourLog.info(myCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
assertEquals("http://localhost:" + ourPort + "/ConceptMap/1/_history/1", conceptMap.getId());
assertEquals(myRestServerDstu3Helper.getBase() + "/ConceptMap/1/_history/1", conceptMap.getId());
assertEquals(CM_URL, conceptMap.getUrl());
assertEquals(VS_URL_1, conceptMap.getSourceUriType().getValueAsString());
@ -317,16 +326,20 @@ public class ImportCsvToConceptMapCommandDstu3Test {
assertEquals(ConceptMapEquivalence.EQUAL, target.getEquivalence());
assertEquals("3d This is a comment.", target.getComment());
App.main(new String[]{"import-csv-to-conceptmap",
"-v", ourVersion,
"-t", ourBase,
"-u", CM_URL,
"-i", VS_URL_1,
"-o", VS_URL_2,
"-f", file,
"-l"});
App.main(myBaseRequestGeneratingCommandTestUtil.createArgs(
new String[]{
ImportCsvToConceptMapCommand.COMMAND,
"-v", myVersion,
"-u", CM_URL,
"-i", VS_URL_1,
"-o", VS_URL_2,
"-f", myFile,
"-l"
},
"-t", theIncludeTls, myRestServerDstu3Helper
));
response = ourClient
response = myRestServerDstu3Helper.getClient()
.search()
.forResource(ConceptMap.class)
.where(ConceptMap.URL.matches().value(CM_URL))
@ -335,34 +348,7 @@ public class ImportCsvToConceptMapCommandDstu3Test {
conceptMap = (ConceptMap) response.getEntryFirstRep().getResource();
assertEquals("http://localhost:" + ourPort + "/ConceptMap/1/_history/2", conceptMap.getId());
assertEquals(myRestServerDstu3Helper.getBase() + "/ConceptMap/1/_history/2", conceptMap.getId());
}
@AfterAll
public static void afterClassClearContext() throws Exception {
JettyUtil.closeServer(ourServer);
TestUtil.randomizeLocaleAndTimezone();
}
@BeforeAll
public static void beforeClass() throws Exception {
ourServer = new Server(0);
ServletHandler servletHandler = new ServletHandler();
restfulServer = new RestfulServer(ourCtx);
restfulServer.registerInterceptor(new VerboseLoggingInterceptor());
restfulServer.setResourceProviders(new HashMapResourceProviderConceptMapDstu3(ourCtx));
ServletHolder servletHolder = new ServletHolder(restfulServer);
servletHandler.addServletWithMapping(servletHolder, "/*");
ourServer.setHandler(servletHandler);
JettyUtil.startServer(ourServer);
ourPort = JettyUtil.getPortForStartedServer(ourServer);
ourBase = "http://localhost:" + ourPort;
ourClient = ourCtx.newRestfulGenericClient(ourBase);
}
}

View File

@ -2,14 +2,9 @@ package ca.uhn.fhir.cli;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.interceptor.VerboseLoggingInterceptor;
import ca.uhn.fhir.test.utilities.JettyUtil;
import ca.uhn.fhir.test.utilities.BaseRequestGeneratingCommandTestUtil;
import ca.uhn.fhir.test.utilities.RestServerR4Helper;
import ca.uhn.fhir.util.TestUtil;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.ConceptMap;
@ -19,8 +14,11 @@ import org.hl7.fhir.r4.model.ConceptMap.TargetElementComponent;
import org.hl7.fhir.r4.model.Enumerations.ConceptMapEquivalence;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import java.io.File;
@ -38,26 +36,32 @@ public class ImportCsvToConceptMapCommandR4Test {
private static final String CS_URL_3 = "http://example.com/codesystem/3";
private static final String FILENAME = "import-csv-to-conceptmap-command-test-input.csv";
private static String file;
private static String ourBase;
private static IGenericClient ourClient;
private static FhirContext ourCtx = FhirContext.forR4();
private static int ourPort;
private static Server ourServer;
private static String ourVersion = "r4";
private static RestfulServer restfulServer;
private static HashMapResourceProviderConceptMapR4 hashMapResourceProviderConceptMapR4;
static {
System.setProperty("test", "true");
}
private final FhirContext myFhirContext = FhirContext.forR4();
private final String myVersion = "r4";
private String myFilePath;
@RegisterExtension
public final RestServerR4Helper myRestServerR4Helper = new RestServerR4Helper(true);
@RegisterExtension
public BaseRequestGeneratingCommandTestUtil myBaseRequestGeneratingCommandTestUtil = new BaseRequestGeneratingCommandTestUtil();
@BeforeEach
public void before(){
myRestServerR4Helper.setConceptMapResourceProvider(new HashMapResourceProviderConceptMapR4(myFhirContext));
}
@AfterEach
public void afterClearResourceProvider() {
HashMapResourceProviderConceptMapR4 resourceProvider = (HashMapResourceProviderConceptMapR4) restfulServer.getResourceProviders().iterator().next();
resourceProvider.clear();
public void afterEach() {
myRestServerR4Helper.clearDataAndCounts();
}
@AfterAll
public static void afterAll(){
TestUtil.randomizeLocaleAndTimezone();
}
@Test
@ -66,7 +70,7 @@ public class ImportCsvToConceptMapCommandR4Test {
String conceptMapUrl = conceptMap.getUrl();
ourLog.info("Searching for existing ConceptMap with specified URL (i.e. ConceptMap.url): {}", conceptMapUrl);
MethodOutcome methodOutcome = ourClient
MethodOutcome methodOutcome = myRestServerR4Helper.getClient()
.update()
.resource(conceptMap)
.conditional()
@ -80,11 +84,11 @@ public class ImportCsvToConceptMapCommandR4Test {
@Test
public void testConditionalUpdateResultsInUpdate() {
ConceptMap conceptMap = ExportConceptMapToCsvCommandR4Test.createConceptMap();
ourClient.create().resource(conceptMap).execute();
myRestServerR4Helper.getClient().create().resource(conceptMap).execute();
String conceptMapUrl = conceptMap.getUrl();
ourLog.info("Searching for existing ConceptMap with specified URL (i.e. ConceptMap.url): {}", conceptMapUrl);
MethodOutcome methodOutcome = ourClient
MethodOutcome methodOutcome = myRestServerR4Helper.getClient()
.update()
.resource(conceptMap)
.conditional()
@ -98,9 +102,9 @@ public class ImportCsvToConceptMapCommandR4Test {
@Test
public void testNonConditionalUpdate() {
ConceptMap conceptMap = ExportConceptMapToCsvCommandR4Test.createConceptMap();
ourClient.create().resource(conceptMap).execute();
myRestServerR4Helper.getClient().create().resource(conceptMap).execute();
Bundle response = ourClient
Bundle response = myRestServerR4Helper.getClient()
.search()
.forResource(ConceptMap.class)
.where(ConceptMap.URL.matches().value(CM_URL))
@ -109,7 +113,7 @@ public class ImportCsvToConceptMapCommandR4Test {
ConceptMap resultConceptMap = (ConceptMap) response.getEntryFirstRep().getResource();
MethodOutcome methodOutcome = ourClient
MethodOutcome methodOutcome = myRestServerR4Helper.getClient()
.update()
.resource(resultConceptMap)
.withId(resultConceptMap.getIdElement())
@ -121,22 +125,27 @@ public class ImportCsvToConceptMapCommandR4Test {
assertTrue(!Boolean.TRUE.equals(methodOutcome.getCreated()));
}
@Test
public void testImportCsvToConceptMapCommand() throws FHIRException {
@ParameterizedTest
@ValueSource(booleans = {true, false})
public void testImportCsvToConceptMapCommand(boolean theIncludeTls) throws Exception {
ClassLoader classLoader = getClass().getClassLoader();
File fileToImport = new File(classLoader.getResource(FILENAME).getFile());
ImportCsvToConceptMapCommandR4Test.file = fileToImport.getAbsolutePath();
myFilePath = fileToImport.getAbsolutePath();
App.main(new String[]{"import-csv-to-conceptmap",
"-v", ourVersion,
"-t", ourBase,
"-u", CM_URL,
"-i", VS_URL_1,
"-o", VS_URL_2,
"-f", file,
"-l"});
App.main(myBaseRequestGeneratingCommandTestUtil.createArgs(
new String[]{
ImportCsvToConceptMapCommand.COMMAND,
"-v", myVersion,
"-u", CM_URL,
"-i", VS_URL_1,
"-o", VS_URL_2,
"-f", myFilePath,
"-l"
},
"-t", theIncludeTls, myRestServerR4Helper
));
Bundle response = ourClient
Bundle response = myRestServerR4Helper.getClient()
.search()
.forResource(ConceptMap.class)
.where(ConceptMap.URL.matches().value(CM_URL))
@ -145,9 +154,9 @@ public class ImportCsvToConceptMapCommandR4Test {
ConceptMap conceptMap = (ConceptMap) response.getEntryFirstRep().getResource();
ourLog.info(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
ourLog.info(myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
assertEquals("http://localhost:" + ourPort + "/ConceptMap/1/_history/1", conceptMap.getId());
assertEquals(myRestServerR4Helper.getBase() + "/ConceptMap/1/_history/1", conceptMap.getId());
assertEquals(CM_URL, conceptMap.getUrl());
assertEquals(VS_URL_1, conceptMap.getSourceUriType().getValueAsString());
@ -323,16 +332,20 @@ public class ImportCsvToConceptMapCommandR4Test {
assertEquals(ConceptMapEquivalence.EQUAL, target.getEquivalence());
assertEquals("3d This is a comment.", target.getComment());
App.main(new String[]{"import-csv-to-conceptmap",
"-v", ourVersion,
"-t", ourBase,
"-u", CM_URL,
"-i", VS_URL_1,
"-o", VS_URL_2,
"-f", file,
"-l"});
App.main(myBaseRequestGeneratingCommandTestUtil.createArgs(
new String[]{
ImportCsvToConceptMapCommand.COMMAND,
"-v", myVersion,
"-u", CM_URL,
"-i", VS_URL_1,
"-o", VS_URL_2,
"-f", myFilePath,
"-l"
},
"-t", theIncludeTls, myRestServerR4Helper
));
response = ourClient
response = myRestServerR4Helper.getClient()
.search()
.forResource(ConceptMap.class)
.where(ConceptMap.URL.matches().value(CM_URL))
@ -341,25 +354,30 @@ public class ImportCsvToConceptMapCommandR4Test {
conceptMap = (ConceptMap) response.getEntryFirstRep().getResource();
assertEquals("http://localhost:" + ourPort + "/ConceptMap/1/_history/2", conceptMap.getId());
assertEquals(myRestServerR4Helper.getBase() + "/ConceptMap/1/_history/2", conceptMap.getId());
}
@Test
public void testImportCsvToConceptMapCommandWithByteOrderMark() throws FHIRException {
@ParameterizedTest
@ValueSource(booleans = {true, false})
public void testImportCsvToConceptMapCommandWithByteOrderMark(boolean theIncludeTls) throws FHIRException {
ClassLoader classLoader = getClass().getClassLoader();
File fileToImport = new File(classLoader.getResource("loinc-to-phenx.csv").getFile());
ImportCsvToConceptMapCommandR4Test.file = fileToImport.getAbsolutePath();
myFilePath = fileToImport.getAbsolutePath();
App.main(new String[]{"import-csv-to-conceptmap",
"-v", ourVersion,
"-t", ourBase,
"-u", "http://loinc.org/cm/loinc-to-phenx",
"-i", "http://loinc.org",
"-o", "http://phenxtoolkit.org",
"-f", file,
"-l"});
App.main(myBaseRequestGeneratingCommandTestUtil.createArgs(
new String[]{
ImportCsvToConceptMapCommand.COMMAND,
"-v", myVersion,
"-u", "http://loinc.org/cm/loinc-to-phenx",
"-i", "http://loinc.org",
"-o", "http://phenxtoolkit.org",
"-f", myFilePath,
"-l"
},
"-t", theIncludeTls, myRestServerR4Helper
));
Bundle response = ourClient
Bundle response = myRestServerR4Helper.getClient()
.search()
.forResource(ConceptMap.class)
.where(ConceptMap.URL.matches().value("http://loinc.org/cm/loinc-to-phenx"))
@ -368,9 +386,9 @@ public class ImportCsvToConceptMapCommandR4Test {
ConceptMap conceptMap = (ConceptMap) response.getEntryFirstRep().getResource();
ourLog.info(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
ourLog.info(myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
assertEquals("http://localhost:" + ourPort + "/ConceptMap/1/_history/1", conceptMap.getId());
assertEquals(myRestServerR4Helper.getBase() + "/ConceptMap/1/_history/1", conceptMap.getId());
assertEquals("http://loinc.org/cm/loinc-to-phenx", conceptMap.getUrl());
assertEquals("http://loinc.org", conceptMap.getSourceUriType().getValueAsString());
@ -398,16 +416,20 @@ public class ImportCsvToConceptMapCommandR4Test {
assertEquals(ConceptMapEquivalence.EQUIVALENT, target.getEquivalence());
assertNull(target.getComment());
App.main(new String[]{"import-csv-to-conceptmap",
"-v", ourVersion,
"-t", ourBase,
"-u", "http://loinc.org/cm/loinc-to-phenx",
"-i", "http://loinc.org",
"-o", "http://phenxtoolkit.org",
"-f", file,
"-l"});
App.main(myBaseRequestGeneratingCommandTestUtil.createArgs(
new String[]{
ImportCsvToConceptMapCommand.COMMAND,
"-v", myVersion,
"-u", "http://loinc.org/cm/loinc-to-phenx",
"-i", "http://loinc.org",
"-o", "http://phenxtoolkit.org",
"-f", myFilePath,
"-l"
},
"-t", theIncludeTls, myRestServerR4Helper
));
response = ourClient
response = myRestServerR4Helper.getClient()
.search()
.forResource(ConceptMap.class)
.where(ConceptMap.URL.matches().value("http://loinc.org/cm/loinc-to-phenx"))
@ -416,34 +438,6 @@ public class ImportCsvToConceptMapCommandR4Test {
conceptMap = (ConceptMap) response.getEntryFirstRep().getResource();
assertEquals("http://localhost:" + ourPort + "/ConceptMap/1/_history/2", conceptMap.getId());
}
@AfterAll
public static void afterClassClearContext() throws Exception {
JettyUtil.closeServer(ourServer);
TestUtil.randomizeLocaleAndTimezone();
}
@BeforeAll
public static void beforeClass() throws Exception {
ourServer = new Server(0);
ServletHandler servletHandler = new ServletHandler();
restfulServer = new RestfulServer(ourCtx);
restfulServer.registerInterceptor(new VerboseLoggingInterceptor());
restfulServer.setResourceProviders(new HashMapResourceProviderConceptMapR4(ourCtx));
ServletHolder servletHolder = new ServletHolder(restfulServer);
servletHandler.addServletWithMapping(servletHolder, "/*");
ourServer.setHandler(servletHandler);
JettyUtil.startServer(ourServer);
ourPort = JettyUtil.getPortForStartedServer(ourServer);
ourBase = "http://localhost:" + ourPort;
ourClient = ourCtx.newRestfulGenericClient(ourBase);
assertEquals(myRestServerR4Helper.getBase() + "/ConceptMap/1/_history/2", conceptMap.getId());
}
}

View File

@ -2,12 +2,15 @@ package ca.uhn.fhir.cli;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.provider.BaseJpaSystemProvider;
import ca.uhn.fhir.test.utilities.server.RestfulServerExtension;
import ca.uhn.fhir.test.utilities.BaseRequestGeneratingCommandTestUtil;
import ca.uhn.fhir.test.utilities.RestServerR4Helper;
import ca.uhn.fhir.util.ParametersUtil;
import org.hl7.fhir.instance.model.api.IBaseParameters;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;
@ -31,8 +34,9 @@ class ReindexTerminologyCommandTest {
private BaseJpaSystemProvider<?, ?> myProvider = spy(new BaseJpaSystemProvider<>());
@RegisterExtension
public final RestfulServerExtension myRestfulServerExtension =
new RestfulServerExtension(myContext, myProvider);
public final RestServerR4Helper myRestServerR4Helper = new RestServerR4Helper(true);
@RegisterExtension
public BaseRequestGeneratingCommandTestUtil myBaseRequestGeneratingCommandTestUtil = new BaseRequestGeneratingCommandTestUtil();
private final ByteArrayOutputStream outputStreamCaptor = new ByteArrayOutputStream();
@ -41,65 +45,85 @@ class ReindexTerminologyCommandTest {
System.setProperty("test", "true");
}
@BeforeEach
public void beforeEach(){
myRestServerR4Helper.registerProvider(myProvider);
}
@Test
public void testProviderMethodInvoked() {
@ParameterizedTest
@ValueSource(booleans = {true, false})
public void testProviderMethodInvoked(boolean theIncludeTls) {
System.setOut(new PrintStream(outputStreamCaptor));
IBaseParameters retVal = ParametersUtil.newInstance(myContext);
ParametersUtil.addParameterToParametersBoolean(myContext, retVal, RESP_PARAM_SUCCESS, true);
doReturn(retVal).when(myProvider).reindexTerminology(any());
App.main(new String[]{
ReindexTerminologyCommand.REINDEX_TERMINOLOGY,
"-v", "r4",
"-t", myRestfulServerExtension.getBaseUrl()
});
App.main(myBaseRequestGeneratingCommandTestUtil.createArgs(
new String[]{
ReindexTerminologyCommand.REINDEX_TERMINOLOGY,
"-v", "r4"
},
"-t", theIncludeTls, myRestServerR4Helper
));
assertThat(outputStreamCaptor.toString().trim(),
outputStreamCaptor.toString().trim(), containsString("<valueBoolean value=\"true\"/>"));
}
@Test
public void testNoVersionThrows() {
@ParameterizedTest
@ValueSource(booleans = {true, false})
public void testNoVersionThrows(boolean theIncludeTls) {
IBaseParameters retVal = ParametersUtil.newInstance(myContext);
ParametersUtil.addParameterToParametersBoolean(myContext, retVal, RESP_PARAM_SUCCESS, true);
doReturn(retVal).when(myProvider).reindexTerminology(any());
Error thrown = assertThrows(Error.class, () ->
App.main(new String[]{
ReindexTerminologyCommand.REINDEX_TERMINOLOGY,
"-t", myRestfulServerExtension.getBaseUrl()
})
);
Error thrown = assertThrows(Error.class, () -> {
App.main(myBaseRequestGeneratingCommandTestUtil.createArgs(
new String[]{
ReindexTerminologyCommand.REINDEX_TERMINOLOGY
},
"-t", theIncludeTls, myRestServerR4Helper
));
});
assertThat(thrown.getMessage(), containsString("Missing required option: v"));
}
@Test
public void testNoTargetThrows() {
@ParameterizedTest
@ValueSource(booleans = {true, false})
public void testNoTargetThrows(boolean theIncludeTls) {
IBaseParameters retVal = ParametersUtil.newInstance(myContext);
ParametersUtil.addParameterToParametersBoolean(myContext, retVal, RESP_PARAM_SUCCESS, true);
doReturn(retVal).when(myProvider).reindexTerminology(any());
Error thrown = assertThrows(Error.class, () ->
App.main(new String[]{ReindexTerminologyCommand.REINDEX_TERMINOLOGY, "-v", "r4"})
);
Error thrown = assertThrows(Error.class, () -> {
App.main(myBaseRequestGeneratingCommandTestUtil.createArgs(
new String[]{
ReindexTerminologyCommand.REINDEX_TERMINOLOGY,
"-v", "r4"
},
null, theIncludeTls, myRestServerR4Helper
));
});
assertThat(thrown.getMessage(), containsString("Missing required option: t"));
}
@Test
public void testHandleUnexpectedResponse() {
@ParameterizedTest
@ValueSource(booleans = {true, false})
public void testHandleUnexpectedResponse(boolean theIncludeTls) {
System.setOut(new PrintStream(outputStreamCaptor));
IBaseParameters retVal = ParametersUtil.newInstance(myContext);
doReturn(retVal).when(myProvider).reindexTerminology(any());
App.main(new String[]{
ReindexTerminologyCommand.REINDEX_TERMINOLOGY,
"-v", "r4",
"-t", myRestfulServerExtension.getBaseUrl()
});
App.main(myBaseRequestGeneratingCommandTestUtil.createArgs(
new String[]{
ReindexTerminologyCommand.REINDEX_TERMINOLOGY,
"-v", "r4"
},
"-t", theIncludeTls, myRestServerR4Helper
));
assertThat(outputStreamCaptor.toString().trim(),
outputStreamCaptor.toString().trim(), containsString("<valueBoolean value=\"false\"/>"));
@ -110,8 +134,9 @@ class ReindexTerminologyCommandTest {
}
@Test
public void testHandleServiceError() {
@ParameterizedTest
@ValueSource(booleans = {true, false})
public void testHandleServiceError(boolean theIncludeTls) {
System.setOut(new PrintStream(outputStreamCaptor));
IBaseParameters retVal = ParametersUtil.newInstance(myContext);
ParametersUtil.addParameterToParametersBoolean(myContext, retVal, RESP_PARAM_SUCCESS, false);
@ -119,11 +144,13 @@ class ReindexTerminologyCommandTest {
"Freetext service is not configured. Operation didn't run.");
doReturn(retVal).when(myProvider).reindexTerminology(any());
App.main(new String[]{
ReindexTerminologyCommand.REINDEX_TERMINOLOGY,
"-v", "r4",
"-t", myRestfulServerExtension.getBaseUrl()
});
App.main(myBaseRequestGeneratingCommandTestUtil.createArgs(
new String[]{
ReindexTerminologyCommand.REINDEX_TERMINOLOGY,
"-v", "r4"
},
"-t", theIncludeTls, myRestServerR4Helper
));
assertThat(outputStreamCaptor.toString().trim(),
outputStreamCaptor.toString().trim(), containsString("<valueBoolean value=\"false\"/>"));

View File

@ -5,20 +5,21 @@ import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
import ca.uhn.fhir.jpa.term.UploadStatistics;
import ca.uhn.fhir.jpa.term.api.ITermLoaderSvc;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.test.utilities.JettyUtil;
import ca.uhn.fhir.test.utilities.BaseRequestGeneratingCommandTestUtil;
import ca.uhn.fhir.test.utilities.BaseRestServerHelper;
import ca.uhn.fhir.test.utilities.RestServerDstu3Helper;
import ca.uhn.fhir.test.utilities.RestServerR4Helper;
import com.google.common.base.Charsets;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
@ -69,8 +70,6 @@ public class UploadTerminologyCommandTest {
private final String myICD10URL = "http://hl7.org/fhir/sid/icd-10-cm";
private final String myICD10FileName = new File("src/test/resources").getAbsolutePath() + "/icd10cm_tabular_2021.xml";
private File myICD10File = new File(myICD10FileName);
private Server myServer;
private int myPort;
@Mock
protected ITermLoaderSvc myTermLoaderSvc;
@ -82,35 +81,43 @@ public class UploadTerminologyCommandTest {
System.setProperty("test", "true");
}
static Stream<String> paramsProvider() {
return Stream.of(FHIR_VERSION_DSTU3, FHIR_VERSION_R4);
static Stream<Arguments> paramsProvider(){
return Stream.of(
// [0] theFhirVersion, [1] theIncludeTls
Arguments.arguments(FHIR_VERSION_DSTU3, true),
Arguments.arguments(FHIR_VERSION_DSTU3, false),
Arguments.arguments(FHIR_VERSION_R4, true),
Arguments.arguments(FHIR_VERSION_R4, false)
);
}
@RegisterExtension
public final RestServerR4Helper myRestServerR4Helper = new RestServerR4Helper(true);
@RegisterExtension
public final RestServerDstu3Helper myRestServerDstu3Helper = new RestServerDstu3Helper(true);
@RegisterExtension
public BaseRequestGeneratingCommandTestUtil myBaseRequestGeneratingCommandTestUtil = new BaseRequestGeneratingCommandTestUtil();
private BaseRestServerHelper myBaseRestServerHelper;
@BeforeEach
public void beforeEach(TestInfo testInfo) throws Exception {
writeConceptAndHierarchyFiles();
if (testInfo.getDisplayName().endsWith(FHIR_VERSION_DSTU3)) {
if (testInfo.getDisplayName().contains(FHIR_VERSION_DSTU3)) {
myCtx = FhirContext.forDstu3();
} else if (testInfo.getDisplayName().endsWith(FHIR_VERSION_R4)) {
myRestServerDstu3Helper.registerProvider(new TerminologyUploaderProvider(myCtx, myTermLoaderSvc));
myBaseRestServerHelper = myRestServerDstu3Helper;
} else if (testInfo.getDisplayName().contains(FHIR_VERSION_R4)) {
myCtx = FhirContext.forR4();
myRestServerR4Helper.registerProvider(new TerminologyUploaderProvider(myCtx, myTermLoaderSvc));
myBaseRestServerHelper = myRestServerR4Helper;
} else {
fail("Unknown FHIR Version param provided: " + testInfo.getDisplayName());
}
myServer = new Server(0);
TerminologyUploaderProvider provider = new TerminologyUploaderProvider(myCtx, myTermLoaderSvc);
ServletHandler proxyHandler = new ServletHandler();
RestfulServer servlet = new RestfulServer(myCtx);
servlet.registerProvider(provider);
ServletHolder servletHolder = new ServletHolder(servlet);
proxyHandler.addServletWithMapping(servletHolder, "/*");
myServer.setHandler(proxyHandler);
JettyUtil.startServer(myServer);
myPort = JettyUtil.getPortForStartedServer(myServer);
}
@AfterEach
public void afterEach() throws Exception {
JettyUtil.closeServer(myServer);
FileUtils.deleteQuietly(myConceptsFile);
FileUtils.deleteQuietly(myHierarchyFile);
FileUtils.deleteQuietly(myCodeSystemFile);
@ -122,7 +129,7 @@ public class UploadTerminologyCommandTest {
@ParameterizedTest
@MethodSource("paramsProvider")
public void testDeltaAdd(String theFhirVersion) throws IOException {
public void testDeltaAdd(String theFhirVersion, boolean theIncludeTls) throws IOException {
if (FHIR_VERSION_DSTU3.equals(theFhirVersion)) {
when(myTermLoaderSvc.loadDeltaAdd(eq("http://foo"), anyList(), any())).thenReturn(new UploadStatistics(100, new org.hl7.fhir.dstu3.model.IdType("CodeSystem/101")));
} else if (FHIR_VERSION_R4.equals(theFhirVersion)) {
@ -131,15 +138,17 @@ public class UploadTerminologyCommandTest {
fail("Unknown FHIR Version param provided: " + theFhirVersion);
}
App.main(new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", theFhirVersion,
"-m", "ADD",
"-t", "http://localhost:" + myPort,
"-u", "http://foo",
"-d", myConceptsFileName,
"-d", myHierarchyFileName
});
App.main(myBaseRequestGeneratingCommandTestUtil.createArgs(
new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", theFhirVersion,
"-m", "ADD",
"-u", "http://foo",
"-d", myConceptsFileName,
"-d", myHierarchyFileName
},
"-t", theIncludeTls, myBaseRestServerHelper
));
verify(myTermLoaderSvc, times(1)).loadDeltaAdd(eq("http://foo"), myDescriptorListCaptor.capture(), any());
@ -151,7 +160,7 @@ public class UploadTerminologyCommandTest {
@ParameterizedTest
@MethodSource("paramsProvider")
public void testDeltaAddUsingCodeSystemResource(String theFhirVersion) throws IOException {
public void testDeltaAddUsingCodeSystemResource(String theFhirVersion, boolean theIncludeTls) throws IOException {
if (FHIR_VERSION_DSTU3.equals(theFhirVersion)) {
try (FileWriter w = new FileWriter(myCodeSystemFile, false)) {
org.hl7.fhir.dstu3.model.CodeSystem cs = new org.hl7.fhir.dstu3.model.CodeSystem();
@ -170,14 +179,16 @@ public class UploadTerminologyCommandTest {
when(myTermLoaderSvc.loadDeltaAdd(eq("http://foo"), anyList(), any())).thenReturn(new UploadStatistics(100, new org.hl7.fhir.r4.model.IdType("CodeSystem/101")));
App.main(new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", theFhirVersion,
"-m", "ADD",
"-t", "http://localhost:" + myPort,
"-u", "http://foo",
"-d", myCodeSystemFileName
});
App.main(myBaseRequestGeneratingCommandTestUtil.createArgs(
new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", theFhirVersion,
"-m", "ADD",
"-u", "http://foo",
"-d", myCodeSystemFileName
},
"-t", theIncludeTls, myBaseRestServerHelper
));
verify(myTermLoaderSvc, times(1)).loadDeltaAdd(eq("http://foo"), myDescriptorListCaptor.capture(), any());
@ -190,7 +201,7 @@ public class UploadTerminologyCommandTest {
@ParameterizedTest
@MethodSource("paramsProvider")
public void testDeltaAddInvalidResource(String theFhirVersion) throws IOException {
public void testDeltaAddInvalidResource(String theFhirVersion, boolean theIncludeTls) throws IOException {
if (FHIR_VERSION_DSTU3.equals(theFhirVersion)) {
try (FileWriter w = new FileWriter(myCodeSystemFile, false)) {
org.hl7.fhir.dstu3.model.Patient patient = new org.hl7.fhir.dstu3.model.Patient();
@ -208,14 +219,16 @@ public class UploadTerminologyCommandTest {
}
try {
App.main(new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", theFhirVersion,
"-m", "ADD",
"-t", "http://localhost:" + myPort,
"-u", "http://foo",
"-d", myCodeSystemFileName
});
App.main(myBaseRequestGeneratingCommandTestUtil.createArgs(
new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", theFhirVersion,
"-m", "ADD",
"-u", "http://foo",
"-d", myCodeSystemFileName
},
"-t", theIncludeTls, myBaseRestServerHelper
));
fail();
} catch (Error e) {
assertThat(e.toString(), containsString("HTTP 400 Bad Request: " + Msg.code(362) + "Request has parameter codeSystem of type Patient but method expects type CodeSystem"));
@ -224,20 +237,23 @@ public class UploadTerminologyCommandTest {
@ParameterizedTest
@MethodSource("paramsProvider")
public void testDeltaAddInvalidFileType(String theFhirVersion) throws IOException {
public void testDeltaAddInvalidFileType(String theFhirVersion, boolean theIncludeTls) throws IOException {
try (FileWriter w = new FileWriter(myTextFileName, false)) {
w.append("Help I'm a Bug");
}
try {
App.main(new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", theFhirVersion,
"-m", "ADD",
"-t", "http://localhost:" + myPort,
"-u", "http://foo",
"-d", myTextFileName
});
App.main(myBaseRequestGeneratingCommandTestUtil.createArgs(
new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", theFhirVersion,
"-m", "ADD",
"-u", "http://foo",
"-d", myTextFileName
},
"-t", theIncludeTls, myBaseRestServerHelper
));
fail();
} catch (Error e) {
assertThat(e.toString(), containsString("Don't know how to handle file:"));
@ -246,19 +262,21 @@ public class UploadTerminologyCommandTest {
@ParameterizedTest
@MethodSource("paramsProvider")
public void testDeltaAddUsingCompressedFile(String theFhirVersion) throws IOException {
public void testDeltaAddUsingCompressedFile(String theFhirVersion, boolean theIncludeTls) throws IOException {
writeArchiveFile(myConceptsFile, myHierarchyFile);
when(myTermLoaderSvc.loadDeltaAdd(eq("http://foo"), anyList(), any())).thenReturn(new UploadStatistics(100, new org.hl7.fhir.r4.model.IdType("CodeSystem/101")));
App.main(new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", theFhirVersion,
"-m", "ADD",
"-t", "http://localhost:" + myPort,
"-u", "http://foo",
"-d", myArchiveFileName
});
App.main(myBaseRequestGeneratingCommandTestUtil.createArgs(
new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", theFhirVersion,
"-m", "ADD",
"-u", "http://foo",
"-d", myArchiveFileName
},
"-t", theIncludeTls, myBaseRestServerHelper
));
verify(myTermLoaderSvc, times(1)).loadDeltaAdd(eq("http://foo"), myDescriptorListCaptor.capture(), any());
@ -270,17 +288,20 @@ public class UploadTerminologyCommandTest {
@ParameterizedTest
@MethodSource("paramsProvider")
public void testDeltaAddInvalidFileName(String theFhirVersion) throws IOException {
public void testDeltaAddInvalidFileName(String theFhirVersion, boolean theIncludeTls) throws IOException {
try {
App.main(new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", theFhirVersion,
"-m", "ADD",
"-t", "http://localhost:" + myPort,
"-u", "http://foo",
"-d", myConceptsFileName + "/foo.csv",
"-d", myHierarchyFileName
});
App.main(myBaseRequestGeneratingCommandTestUtil.createArgs(
new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", theFhirVersion,
"-m", "ADD",
"-u", "http://foo",
"-d", myConceptsFileName + "/foo.csv",
"-d", myHierarchyFileName
},
"-t", theIncludeTls, myBaseRestServerHelper
));
fail();
} catch (Error e) {
assertThat(e.toString(), Matchers.containsString("FileNotFoundException: target/concepts.csv/foo.csv"));
}
@ -288,7 +309,7 @@ public class UploadTerminologyCommandTest {
@ParameterizedTest
@MethodSource("paramsProvider")
public void testDeltaRemove(String theFhirVersion) throws IOException {
public void testDeltaRemove(String theFhirVersion, boolean theIncludeTls) throws IOException {
if (FHIR_VERSION_DSTU3.equals(theFhirVersion)) {
when(myTermLoaderSvc.loadDeltaRemove(eq("http://foo"), anyList(), any())).thenReturn(new UploadStatistics(100, new org.hl7.fhir.dstu3.model.IdType("CodeSystem/101")));
} else if (FHIR_VERSION_R4.equals(theFhirVersion)) {
@ -297,15 +318,17 @@ public class UploadTerminologyCommandTest {
fail("Unknown FHIR Version param provided: " + theFhirVersion);
}
App.main(new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", theFhirVersion,
"-m", "REMOVE",
"-t", "http://localhost:" + myPort,
"-u", "http://foo",
"-d", myConceptsFileName,
"-d", myHierarchyFileName
});
App.main(myBaseRequestGeneratingCommandTestUtil.createArgs(
new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", theFhirVersion,
"-m", "REMOVE",
"-u", "http://foo",
"-d", myConceptsFileName,
"-d", myHierarchyFileName
},
"-t", theIncludeTls, myBaseRestServerHelper
));
verify(myTermLoaderSvc, times(1)).loadDeltaRemove(eq("http://foo"), myDescriptorListCaptor.capture(), any());
@ -317,7 +340,7 @@ public class UploadTerminologyCommandTest {
@ParameterizedTest
@MethodSource("paramsProvider")
public void testSnapshot(String theFhirVersion) throws IOException {
public void testSnapshot(String theFhirVersion, boolean theIncludeTls) throws IOException {
if (FHIR_VERSION_DSTU3.equals(theFhirVersion)) {
when(myTermLoaderSvc.loadCustom(any(), anyList(), any())).thenReturn(new UploadStatistics(100, new org.hl7.fhir.dstu3.model.IdType("CodeSystem/101")));
} else if (FHIR_VERSION_R4.equals(theFhirVersion)) {
@ -326,15 +349,17 @@ public class UploadTerminologyCommandTest {
fail("Unknown FHIR Version param provided: " + theFhirVersion);
}
App.main(new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", theFhirVersion,
"-m", "SNAPSHOT",
"-t", "http://localhost:" + myPort,
"-u", "http://foo",
"-d", myConceptsFileName,
"-d", myHierarchyFileName
});
App.main(myBaseRequestGeneratingCommandTestUtil.createArgs(
new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", theFhirVersion,
"-m", "SNAPSHOT",
"-u", "http://foo",
"-d", myConceptsFileName,
"-d", myHierarchyFileName
},
"-t", theIncludeTls, myBaseRestServerHelper
));
verify(myTermLoaderSvc, times(1)).loadCustom(any(), myDescriptorListCaptor.capture(), any());
@ -346,7 +371,7 @@ public class UploadTerminologyCommandTest {
@ParameterizedTest
@MethodSource("paramsProvider")
public void testPropertiesFile(String theFhirVersion) throws IOException {
public void testPropertiesFile(String theFhirVersion, boolean theIncludeTls) throws IOException {
try (FileWriter w = new FileWriter(myPropertiesFileName, false)) {
w.append("a=b\n");
}
@ -359,14 +384,16 @@ public class UploadTerminologyCommandTest {
fail("Unknown FHIR Version param provided: " + theFhirVersion);
}
App.main(new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", theFhirVersion,
"-m", "SNAPSHOT",
"-t", "http://localhost:" + myPort,
"-u", "http://foo",
"-d", myPropertiesFileName,
});
App.main(myBaseRequestGeneratingCommandTestUtil.createArgs(
new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", theFhirVersion,
"-m", "SNAPSHOT",
"-u", "http://foo",
"-d", myPropertiesFileName
},
"-t", theIncludeTls, myBaseRestServerHelper
));
verify(myTermLoaderSvc, times(1)).loadCustom(any(), myDescriptorListCaptor.capture(), any());
@ -378,7 +405,7 @@ public class UploadTerminologyCommandTest {
@ParameterizedTest
@MethodSource("paramsProvider")
public void testSnapshotLargeFile(String theFhirVersion) throws IOException {
public void testSnapshotLargeFile(String theFhirVersion, boolean theIncludeTls) throws IOException {
UploadTerminologyCommand.setTransferSizeLimitForUnitTest(10);
if (FHIR_VERSION_DSTU3.equals(theFhirVersion)) {
@ -389,15 +416,17 @@ public class UploadTerminologyCommandTest {
fail("Unknown FHIR Version param provided: " + theFhirVersion);
}
App.main(new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", theFhirVersion,
"-m", "SNAPSHOT",
"-t", "http://localhost:" + myPort,
"-u", "http://foo",
"-d", myConceptsFileName,
"-d", myHierarchyFileName
});
App.main(myBaseRequestGeneratingCommandTestUtil.createArgs(
new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", theFhirVersion,
"-m", "SNAPSHOT",
"-u", "http://foo",
"-d", myConceptsFileName,
"-d", myHierarchyFileName
},
"-t", theIncludeTls, myBaseRestServerHelper
));
verify(myTermLoaderSvc, times(1)).loadCustom(any(), myDescriptorListCaptor.capture(), any());
@ -409,7 +438,7 @@ public class UploadTerminologyCommandTest {
@ParameterizedTest
@MethodSource("paramsProvider")
public void testUploadICD10UsingCompressedFile(String theFhirVersion) throws IOException {
public void testUploadICD10UsingCompressedFile(String theFhirVersion, boolean theIncludeTls) throws IOException {
if (FHIR_VERSION_DSTU3.equals(theFhirVersion)) {
when(myTermLoaderSvc.loadIcd10cm(anyList(), any())).thenReturn(new UploadStatistics(100, new org.hl7.fhir.dstu3.model.IdType("CodeSystem/101")));
} else if (FHIR_VERSION_R4.equals(theFhirVersion)) {
@ -418,13 +447,15 @@ public class UploadTerminologyCommandTest {
fail("Unknown FHIR Version param provided: " + theFhirVersion);
}
App.main(new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", theFhirVersion,
"-t", "http://localhost:" + myPort,
"-u", myICD10URL,
"-d", myICD10FileName
});
App.main(myBaseRequestGeneratingCommandTestUtil.createArgs(
new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", theFhirVersion,
"-u", myICD10URL,
"-d", myICD10FileName
},
"-t", theIncludeTls, myBaseRestServerHelper
));
verify(myTermLoaderSvc, times(1)).loadIcd10cm(myDescriptorListCaptor.capture(), any());

View File

@ -0,0 +1,73 @@
package client;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.rest.client.apache.ApacheRestfulClientFactory;
import ca.uhn.fhir.test.BaseFhirVersionParameterizedTest;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.util.EntityUtils;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import javax.net.ssl.SSLHandshakeException;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class ApacheNativeClientTest extends BaseFhirVersionParameterizedTest {
@ParameterizedTest
@MethodSource("baseParamsProvider")
public void testNativeClientHttp(FhirVersionEnum theFhirVersion) {
FhirVersionParams fhirVersionParams = getFhirVersionParams(theFhirVersion);
ApacheRestfulClientFactory clientFactory = new ApacheRestfulClientFactory(fhirVersionParams.getFhirContext());
HttpClient client = clientFactory.getNativeHttpClient();
assertDoesNotThrow(() -> {
HttpUriRequest request = new HttpGet(fhirVersionParams.getPatientEndpoint());
HttpResponse response = client.execute(request);
assertEquals(200, response.getStatusLine().getStatusCode());
String json = EntityUtils.toString(response.getEntity());
IBaseResource bundle = fhirVersionParams.parseResource(json);
assertEquals(fhirVersionParams.getFhirVersion(), bundle.getStructureFhirVersionEnum());
});
}
@ParameterizedTest
@MethodSource("baseParamsProvider")
public void testNativeClientHttps(FhirVersionEnum theFhirVersion) {
FhirVersionParams fhirVersionParams = getFhirVersionParams(theFhirVersion);
ApacheRestfulClientFactory clientFactory = new ApacheRestfulClientFactory(fhirVersionParams.getFhirContext());
HttpClient authenticatedClient = clientFactory.getNativeHttpClient(getTlsAuthentication());
assertDoesNotThrow(() -> {
HttpUriRequest request = new HttpGet(fhirVersionParams.getSecuredPatientEndpoint());
HttpResponse response = authenticatedClient.execute(request);
assertEquals(200, response.getStatusLine().getStatusCode());
String json = EntityUtils.toString(response.getEntity());
IBaseResource bundle = fhirVersionParams.parseResource(json);
assertEquals(fhirVersionParams.getFhirVersion(), bundle.getStructureFhirVersionEnum());
});
}
@ParameterizedTest
@MethodSource("baseParamsProvider")
public void testNativeClientHttpsNoCredentials(FhirVersionEnum theFhirVersion) {
FhirVersionParams fhirVersionParams = getFhirVersionParams(theFhirVersion);
ApacheRestfulClientFactory clientFactory = new ApacheRestfulClientFactory(fhirVersionParams.getFhirContext());
HttpClient unauthenticatedClient = clientFactory.getNativeHttpClient();
assertThrows(SSLHandshakeException.class, () -> {
HttpUriRequest request = new HttpGet(fhirVersionParams.getSecuredPatientEndpoint());
unauthenticatedClient.execute(request);
});
}
}

View File

@ -57,6 +57,12 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-r4</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<!-- Unit test dependencies -->
<dependency>

View File

@ -6,9 +6,15 @@ import ca.uhn.fhir.rest.client.api.Header;
import ca.uhn.fhir.rest.client.api.IHttpClient;
import ca.uhn.fhir.rest.client.impl.RestfulClientFactory;
import ca.uhn.fhir.rest.https.TlsAuthentication;
import ca.uhn.fhir.rest.https.TlsAuthenticationSvc;
import ca.uhn.fhir.rest.https.TrustStoreInfo;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.List;
@ -25,18 +31,18 @@ public class OkHttpRestfulClientFactory extends RestfulClientFactory {
private Call.Factory myNativeClient;
public OkHttpRestfulClientFactory() {
super();
}
public OkHttpRestfulClientFactory() {
super();
}
public OkHttpRestfulClientFactory(FhirContext theFhirContext) {
super(theFhirContext);
}
public OkHttpRestfulClientFactory(FhirContext theFhirContext) {
super(theFhirContext);
}
@Override
protected IHttpClient getHttpClient(String theServerBase) {
return getHttpClient(theServerBase, Optional.empty());
}
@Override
protected IHttpClient getHttpClient(String theServerBase) {
return getHttpClient(theServerBase, Optional.empty());
}
@Override
protected IHttpClient getHttpClient(String theServerBase, Optional<TlsAuthentication> theTlsAuthentication) {
@ -44,52 +50,70 @@ public class OkHttpRestfulClientFactory extends RestfulClientFactory {
}
@Override
protected void resetHttpClient() {
myNativeClient = null;
}
protected void resetHttpClient() {
myNativeClient = null;
}
public synchronized Call.Factory getNativeClient() {
return getNativeClient(Optional.empty());
}
// FIXME ND add authentication
public synchronized Call.Factory getNativeClient(Optional<TlsAuthentication> theTlsAuthentication) {
if (myNativeClient == null) {
myNativeClient = new OkHttpClient()
.newBuilder()
public synchronized Call.Factory getNativeClient(Optional<TlsAuthentication> theTlsAuthentication) {
if (myNativeClient == null) {
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder()
.connectTimeout(getConnectTimeout(), TimeUnit.MILLISECONDS)
.readTimeout(getSocketTimeout(), TimeUnit.MILLISECONDS)
.writeTimeout(getSocketTimeout(), TimeUnit.MILLISECONDS)
.build();
}
.readTimeout(getSocketTimeout(), TimeUnit.MILLISECONDS)
.writeTimeout(getSocketTimeout(), TimeUnit.MILLISECONDS);
return myNativeClient;
}
Optional<SSLContext> optionalSslContext = TlsAuthenticationSvc.createSslContext(theTlsAuthentication);
if (optionalSslContext.isPresent()) {
SSLContext sslContext = optionalSslContext.get();
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
Optional<TrustStoreInfo> trustStoreInfo = theTlsAuthentication.get().getTrustStoreInfo();
X509TrustManager trustManager = TlsAuthenticationSvc.createTrustManager(trustStoreInfo);
clientBuilder.sslSocketFactory(sslSocketFactory, trustManager);
HostnameVerifier hostnameVerifier = TlsAuthenticationSvc.createHostnameVerifier(trustStoreInfo);
clientBuilder.hostnameVerifier(hostnameVerifier);
}
myNativeClient = (Call.Factory) clientBuilder.build();
}
@Override
public IHttpClient getHttpClient(StringBuilder theUrl,
Map<String, List<String>> theIfNoneExistParams,
String theIfNoneExistString,
RequestTypeEnum theRequestType,
List<Header> theHeaders) {
return new OkHttpRestfulClient(getNativeClient(), theUrl, theIfNoneExistParams, theIfNoneExistString, theRequestType, theHeaders);
}
return myNativeClient;
}
/**
* Only accepts clients of type {@link OkHttpClient}
*
* @param okHttpClient
*/
@Override
public void setHttpClient(Object okHttpClient) {
myNativeClient = (Call.Factory) okHttpClient;
}
@Override
public IHttpClient getHttpClient(StringBuilder theUrl,
Map<String, List<String>> theIfNoneExistParams,
String theIfNoneExistString,
RequestTypeEnum theRequestType,
List<Header> theHeaders) {
return getHttpClient(theUrl, Optional.empty(), theIfNoneExistParams, theIfNoneExistString, theRequestType, theHeaders);
}
@Override
public void setProxy(String theHost, Integer thePort) {
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(theHost, thePort));
OkHttpClient.Builder builder = ((OkHttpClient)getNativeClient()).newBuilder().proxy(proxy);
setHttpClient(builder.build());
}
@Override
public IHttpClient getHttpClient(StringBuilder theUrl,
Optional<TlsAuthentication> theTlsAuthentication,
Map<String, List<String>> theIfNoneExistParams,
String theIfNoneExistString,
RequestTypeEnum theRequestType,
List<Header> theHeaders) {
return new OkHttpRestfulClient(getNativeClient(theTlsAuthentication), theUrl, theIfNoneExistParams, theIfNoneExistString, theRequestType, theHeaders);
}
/**
* Only accepts clients of type {@link OkHttpClient}
*
* @param okHttpClient
*/
@Override
public void setHttpClient(Object okHttpClient) {
myNativeClient = (Call.Factory) okHttpClient;
}
@Override
public void setProxy(String theHost, Integer thePort) {
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(theHost, thePort));
OkHttpClient.Builder builder = ((OkHttpClient) getNativeClient()).newBuilder().proxy(proxy);
setHttpClient(builder.build());
}
}

View File

@ -1,16 +1,28 @@
package ca.uhn.fhir.okhttp;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.okhttp.client.OkHttpRestfulClientFactory;
import ca.uhn.fhir.test.BaseFhirVersionParameterizedTest;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import javax.net.ssl.SSLHandshakeException;
import java.util.concurrent.TimeUnit;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class OkHttpRestfulClientFactoryTest {
public class OkHttpRestfulClientFactoryTest extends BaseFhirVersionParameterizedTest {
private OkHttpRestfulClientFactory clientFactory;
@ -56,4 +68,60 @@ public class OkHttpRestfulClientFactoryTest {
assertEquals(1516, ((OkHttpClient)clientFactory.getNativeClient()).connectTimeoutMillis());
}
@ParameterizedTest
@MethodSource("baseParamsProvider")
public void testNativeClientHttp(FhirVersionEnum theFhirVersion) {
FhirVersionParams fhirVersionParams = getFhirVersionParams(theFhirVersion);
OkHttpRestfulClientFactory clientFactory = new OkHttpRestfulClientFactory(fhirVersionParams.getFhirContext());
OkHttpClient client = (OkHttpClient) clientFactory.getNativeClient();
assertDoesNotThrow(() -> {
Request request = new Request.Builder()
.url(fhirVersionParams.getPatientEndpoint())
.build();
Response response = client.newCall(request).execute();
assertEquals(200, response.code());
String json = response.body().string();
IBaseResource bundle = fhirVersionParams.getFhirContext().newJsonParser().parseResource(json);
assertEquals(fhirVersionParams.getFhirVersion(), bundle.getStructureFhirVersionEnum());
});
}
@ParameterizedTest
@MethodSource("baseParamsProvider")
public void testNativeClientHttps(FhirVersionEnum theFhirVersion) {
FhirVersionParams fhirVersionParams = getFhirVersionParams(theFhirVersion);
OkHttpRestfulClientFactory clientFactory = new OkHttpRestfulClientFactory(fhirVersionParams.getFhirContext());
OkHttpClient authenticatedClient = (OkHttpClient) clientFactory.getNativeClient(getTlsAuthentication());
assertDoesNotThrow(() -> {
Request request = new Request.Builder()
.url(fhirVersionParams.getSecuredPatientEndpoint())
.build();
Response response = authenticatedClient.newCall(request).execute();
assertEquals(200, response.code());
String json = response.body().string();
IBaseResource bundle = fhirVersionParams.getFhirContext().newJsonParser().parseResource(json);
assertEquals(fhirVersionParams.getFhirVersion(), bundle.getStructureFhirVersionEnum());
});
}
@ParameterizedTest
@MethodSource("baseParamsProvider")
public void testNativeClientHttpsNoCredentials(FhirVersionEnum theFhirVersion) {
FhirVersionParams fhirVersionParams = getFhirVersionParams(theFhirVersion);
OkHttpRestfulClientFactory clientFactory = new OkHttpRestfulClientFactory(fhirVersionParams.getFhirContext());
OkHttpClient unauthenticatedClient = (OkHttpClient) clientFactory.getNativeClient();
assertThrows(SSLHandshakeException.class, () -> {
Request request = new Request.Builder()
.url(fhirVersionParams.getSecuredPatientEndpoint())
.build();
unauthenticatedClient.newCall(request).execute();
});
}
}

View File

@ -25,9 +25,8 @@ import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.client.api.Header;
import ca.uhn.fhir.rest.client.api.IHttpClient;
import ca.uhn.fhir.rest.client.impl.RestfulClientFactory;
import ca.uhn.fhir.rest.https.KeyStoreInfo;
import ca.uhn.fhir.rest.https.TlsAuthentication;
import ca.uhn.fhir.rest.https.TrustStoreInfo;
import ca.uhn.fhir.rest.https.TlsAuthenticationSvc;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
@ -38,19 +37,13 @@ import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.ProxyAuthenticationStrategy;
import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.PrivateKeyStrategy;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.SSLContexts;
import javax.net.ssl.SSLContext;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@ -65,8 +58,6 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
*/
public class ApacheRestfulClientFactory extends RestfulClientFactory {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ApacheRestfulClientFactory.class);
private HttpClient myHttpClient;
private HttpHost myProxy;
@ -89,8 +80,7 @@ public class ApacheRestfulClientFactory extends RestfulClientFactory {
@Override
protected synchronized ApacheHttpClient getHttpClient(String theServerBase) {
return new ApacheHttpClient(getNativeHttpClient(), new StringBuilder(theServerBase),
null, null, null, null);
return getHttpClient(theServerBase, Optional.empty());
}
@Override
@ -101,8 +91,15 @@ public class ApacheRestfulClientFactory extends RestfulClientFactory {
@Override
public synchronized IHttpClient getHttpClient(StringBuilder theUrl, Map<String, List<String>> theIfNoneExistParams,
String theIfNoneExistString, RequestTypeEnum theRequestType, List<Header> theHeaders) {
return new ApacheHttpClient(getNativeHttpClient(), theUrl, theIfNoneExistParams, theIfNoneExistString, theRequestType,
theHeaders);
return getHttpClient(theUrl, Optional.empty(), theIfNoneExistParams, theIfNoneExistString, theRequestType, theHeaders);
}
@Override
public synchronized IHttpClient getHttpClient(StringBuilder theUrl, Optional<TlsAuthentication> theTlsAuthentication,
Map<String, List<String>> theIfNoneExistParams, String theIfNoneExistString,
RequestTypeEnum theRequestType, List<Header> theHeaders) {
return new ApacheHttpClient(getNativeHttpClient(theTlsAuthentication), theUrl, theIfNoneExistParams, theIfNoneExistString, theRequestType,
theHeaders);
}
public HttpClient getNativeHttpClient() {
@ -127,9 +124,11 @@ public class ApacheRestfulClientFactory extends RestfulClientFactory {
.setDefaultRequestConfig(defaultRequestConfig)
.disableCookieManagement();
SSLConnectionSocketFactory sslConnectionSocketFactory = createSslConnectionSocketFactory(theTlsAuthentication);
Optional<SSLContext> optionalSslContext = TlsAuthenticationSvc.createSslContext(theTlsAuthentication);
PoolingHttpClientConnectionManager connectionManager;
if(sslConnectionSocketFactory != null){
if(optionalSslContext.isPresent()){
SSLContext sslContext = optionalSslContext.get();
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext);
builder.setSSLSocketFactory(sslConnectionSocketFactory);
Registry<ConnectionSocketFactory> registry = RegistryBuilder
.<ConnectionSocketFactory> create()
@ -162,37 +161,6 @@ public class ApacheRestfulClientFactory extends RestfulClientFactory {
return myHttpClient;
}
private SSLConnectionSocketFactory createSslConnectionSocketFactory(Optional<TlsAuthentication> theTlsAuthentication){
if(theTlsAuthentication.isEmpty()){
return null;
}
try{
SSLContextBuilder contextBuilder = SSLContexts.custom();
TlsAuthentication tlsAuth = theTlsAuthentication.get();
if(tlsAuth.getKeyStoreInfo().isPresent()){
KeyStoreInfo keyStoreInfo = tlsAuth.getKeyStoreInfo().get();
PrivateKeyStrategy privateKeyStrategy = null;
if(isNotBlank(keyStoreInfo.getAlias())){
privateKeyStrategy = (aliases, socket) -> keyStoreInfo.getAlias();
}
contextBuilder.loadKeyMaterial(new File(keyStoreInfo.getFilePath()), keyStoreInfo.getStorePass(), keyStoreInfo.getKeyPass(), privateKeyStrategy);
}
if(tlsAuth.getTrustStoreInfo().isPresent()){
TrustStoreInfo trustStoreInfo = tlsAuth.getTrustStoreInfo().get();
contextBuilder.loadTrustMaterial(new File(trustStoreInfo.getFilePath()), trustStoreInfo.getStorePass(), TrustSelfSignedStrategy.INSTANCE);
}
SSLContext sslContext = contextBuilder.build();
return new SSLConnectionSocketFactory(sslContext);
}
catch (Exception e){
throw new RuntimeException(e);
}
}
protected HttpClientBuilder getHttpClientBuilder() {
return HttpClients.custom();
}

View File

@ -384,7 +384,9 @@ public abstract class RestfulClientFactory implements IRestfulClientFactory {
* Get the http client for the given server base
*
* @param theServerBase
* the server base
* the server base
* @param theTlsAuthentication
* Optional configuration to authenticate HTTPS server requests
* @return the http client
*/
protected abstract IHttpClient getHttpClient(String theServerBase, Optional<TlsAuthentication> theTlsAuthentication);

View File

@ -1,39 +1,20 @@
package ca.uhn.fhir.jaxrs.client;
import ca.uhn.fhir.i18n.Msg;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
/*
* #%L
* HAPI FHIR JAX-RS Server
* %%
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
* %%
* 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.
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.client.api.Header;
import ca.uhn.fhir.rest.client.api.IHttpClient;
import ca.uhn.fhir.rest.client.impl.RestfulClientFactory;
import ca.uhn.fhir.rest.https.TlsAuthentication;
import ca.uhn.fhir.rest.https.TlsAuthenticationSvc;
import javax.net.ssl.SSLContext;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import java.util.List;
import java.util.Map;
import java.util.Optional;
/**
* A Restful Client Factory, based on Jax Rs
@ -68,24 +49,33 @@ public class JaxRsRestfulClientFactory extends RestfulClientFactory {
}
public synchronized Client getNativeClientClient(Optional<TlsAuthentication> theTlsAuthentication) {
//FIXME - add HTTPS
if (myNativeClient == null) {
ClientBuilder builder = ClientBuilder.newBuilder();
Optional<SSLContext> optionalSslContext = TlsAuthenticationSvc.createSslContext(theTlsAuthentication);
if(optionalSslContext.isPresent()){
SSLContext sslContext = optionalSslContext.get();
builder.sslContext(sslContext);
}
myNativeClient = builder.build();
}
if (registeredComponents != null && !registeredComponents.isEmpty()) {
for (Class<?> c : registeredComponents) {
myNativeClient = myNativeClient.register(c);
}
}
if (registeredComponents != null && !registeredComponents.isEmpty()) {
for (Class<?> c : registeredComponents) {
myNativeClient = myNativeClient.register(c);
}
}
return myNativeClient;
}
@Override
public synchronized IHttpClient getHttpClient(StringBuilder url, Map<String, List<String>> theIfNoneExistParams, String theIfNoneExistString, RequestTypeEnum theRequestType, List<Header> theHeaders) {
Client client = getNativeClientClient();
return getHttpClient(url, Optional.empty(), theIfNoneExistParams, theIfNoneExistString, theRequestType, theHeaders);
}
@Override
public synchronized IHttpClient getHttpClient(StringBuilder url, Optional<TlsAuthentication> theTlsAuthentication, Map<String, List<String>> theIfNoneExistParams, String theIfNoneExistString, RequestTypeEnum theRequestType, List<Header> theHeaders) {
Client client = getNativeClientClient(theTlsAuthentication);
return new JaxRsHttpClient(client, url, theIfNoneExistParams, theIfNoneExistString, theRequestType, theHeaders);
}

View File

@ -1,29 +1,46 @@
package ca.uhn.fhir.jaxrs.client;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.test.BaseFhirVersionParameterizedTest;
import com.google.common.net.MediaType;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.SSLHandshakeException;
import javax.ws.rs.ProcessingException;
import javax.ws.rs.client.Client;
import javax.ws.rs.core.Response;
import java.util.ArrayList;
import java.util.Arrays;
import static org.hamcrest.CoreMatchers.hasItem;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.IsNot.not;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
/**
* Created by Sebastien Riviere on 31/07/2017.
*/
public class JaxRsRestfulClientFactoryTest {
public class JaxRsRestfulClientFactoryTest extends BaseFhirVersionParameterizedTest {
private static final Logger ourLog = LoggerFactory.getLogger(JaxRsRestfulClientFactoryTest.class);
private final FhirContext context = FhirContext.forDstu2();
private JaxRsRestfulClientFactory factory;
@BeforeEach
public void beforeEach() throws Exception {
factory = new JaxRsRestfulClientFactory(context);
}
@Test
public void emptyConstructorTest() {
assertNotNull(new JaxRsRestfulClientFactory());
@ -52,8 +69,59 @@ public class JaxRsRestfulClientFactoryTest {
assertThat(result.getConfiguration().getClasses(), hasItem(ca.uhn.fhir.jaxrs.client.MyFilter.class));
}
@BeforeEach
public void setUp() {
factory = new JaxRsRestfulClientFactory(context);
@ParameterizedTest
@MethodSource("baseParamsProvider")
public void testNativeClientHttp(FhirVersionEnum theFhirVersion) {
FhirVersionParams fhirVersionParams = getFhirVersionParams(theFhirVersion);
JaxRsRestfulClientFactory factory = new JaxRsRestfulClientFactory(fhirVersionParams.getFhirContext());
Client client = factory.getNativeClientClient();
assertDoesNotThrow(() -> {
Response response = client
.target(fhirVersionParams.getPatientEndpoint())
.request(MediaType.JSON_UTF_8.toString())
.get(Response.class);
assertEquals(200, response.getStatus());
String json = response.readEntity(String.class);
IBaseResource bundle = fhirVersionParams.parseResource(json);
assertEquals(fhirVersionParams.getFhirVersion(), bundle.getStructureFhirVersionEnum());
});
}
@ParameterizedTest
@MethodSource("baseParamsProvider")
public void testNativeClientHttps(FhirVersionEnum theFhirVersion) {
FhirVersionParams fhirVersionParams = getFhirVersionParams(theFhirVersion);
JaxRsRestfulClientFactory factory = new JaxRsRestfulClientFactory(fhirVersionParams.getFhirContext());
Client authenticatedClient = factory.getNativeClientClient(getTlsAuthentication());
assertDoesNotThrow(() -> {
Response response = authenticatedClient
.target(fhirVersionParams.getSecuredPatientEndpoint())
.request(MediaType.JSON_UTF_8.toString())
.get(Response.class);
assertEquals(200, response.getStatus());
String json = response.readEntity(String.class);
IBaseResource bundle = fhirVersionParams.parseResource(json);
assertEquals(fhirVersionParams.getFhirVersion(), bundle.getStructureFhirVersionEnum());
});
}
@ParameterizedTest
@MethodSource("baseParamsProvider")
public void testNativeClientHttpsNoCredentials(FhirVersionEnum theFhirVersion) {
FhirVersionParams fhirVersionParams = getFhirVersionParams(theFhirVersion);
JaxRsRestfulClientFactory factory = new JaxRsRestfulClientFactory(fhirVersionParams.getFhirContext());
Client unauthenticatedClient = factory.getNativeClientClient();
Throwable thrown = assertThrows(ProcessingException.class, () -> {
unauthenticatedClient
.target(fhirVersionParams.getSecuredPatientEndpoint())
.request(MediaType.JSON_UTF_8.toString())
.get(Response.class);
});
assertEquals(SSLHandshakeException.class, thrown.getCause().getClass());
}
}

View File

@ -0,0 +1,83 @@
package ca.uhn.fhir.test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.rest.https.TlsAuthentication;
import ca.uhn.fhir.test.utilities.BaseRequestGeneratingCommandTestUtil;
import ca.uhn.fhir.test.utilities.BaseRestServerHelper;
import ca.uhn.fhir.test.utilities.RestServerDstu3Helper;
import ca.uhn.fhir.test.utilities.RestServerR4Helper;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.params.provider.Arguments;
import java.util.Optional;
import java.util.stream.Stream;
public class BaseFhirVersionParameterizedTest {
@RegisterExtension
public final RestServerR4Helper myRestServerR4Helper = new RestServerR4Helper();
@RegisterExtension
public final RestServerDstu3Helper myRestServerDstu3Helper = new RestServerDstu3Helper();
@RegisterExtension
public BaseRequestGeneratingCommandTestUtil myBaseRequestGeneratingCommandTestUtil = new BaseRequestGeneratingCommandTestUtil();
protected final FhirContext myR4FhirContext = FhirContext.forR4();
protected final FhirContext myDstu3FhirContext = FhirContext.forDstu3();
protected static Stream<Arguments> baseParamsProvider(){
return Stream.of(
Arguments.arguments(FhirVersionEnum.R4),
Arguments.arguments(FhirVersionEnum.DSTU3)
);
}
protected FhirVersionParams getFhirVersionParams(FhirVersionEnum theFhirVersion){
switch(theFhirVersion){
case R4:
return new FhirVersionParams(myRestServerR4Helper, myR4FhirContext);
case DSTU3:
return new FhirVersionParams(myRestServerDstu3Helper, myDstu3FhirContext);
default:
throw new RuntimeException("Unknown FHIR Version param provided: " + theFhirVersion);
}
}
protected Optional<TlsAuthentication> getTlsAuthentication(){
return myBaseRequestGeneratingCommandTestUtil.getTlsAuthentication();
}
protected class FhirVersionParams {
private final BaseRestServerHelper myBaseRestServerHelper;
private final FhirContext myFhirContext;
private final FhirVersionEnum myFhirVersion;
public FhirVersionParams(BaseRestServerHelper theBaseRestServerHelper, FhirContext theFhirContext) {
myBaseRestServerHelper = theBaseRestServerHelper;
myFhirContext = theFhirContext;
myFhirVersion = theFhirContext.getVersion().getVersion();
}
public FhirContext getFhirContext() {
return myFhirContext;
}
public FhirVersionEnum getFhirVersion() {
return myFhirVersion;
}
public String getPatientEndpoint(){
return myBaseRestServerHelper.getBase()+"/Patient";
}
public String getSecuredPatientEndpoint(){
return myBaseRestServerHelper.getSecureBase()+"/Patient";
}
public IBaseResource parseResource(String json){
return myFhirContext.newJsonParser().parseResource(json);
}
}
}

View File

@ -1,69 +0,0 @@
package ca.uhn.fhir.test;
/*-
* #%L
* HAPI FHIR Test Utilities
* %%
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
* %%
* 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.
* #L%
*/
import ca.uhn.fhir.test.utilities.BaseRestServerHelper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.io.Files;
import org.apache.commons.io.IOUtils;
import java.io.File;
import java.io.FileWriter;
import java.net.URL;
import java.nio.charset.StandardCharsets;
public class TlsAuthenticationUtil {
private TlsAuthenticationUtil(){}
public static File createTlsAuthenticationFile() {
try {
ObjectMapper mapper = new ObjectMapper();
ObjectNode keyStore = mapper.createObjectNode();
URL keyStoreUrl = TlsAuthenticationUtil.class.getResource("/tls/client-keystore.p12");
keyStore.put("filePath", keyStoreUrl.getPath());
keyStore.put("storePass", "changeit");
keyStore.put("keyPass", "changeit");
keyStore.put("alias", "1");
ObjectNode trustStore = mapper.createObjectNode();
URL trustStoreUrl = TlsAuthenticationUtil.class.getResource("/tls/client-truststore.p12");
trustStore.put("filePath", trustStoreUrl.getPath());
trustStore.put("storePass", "changeit");
ObjectNode json = mapper.createObjectNode();
json.set("keyStore", keyStore);
json.set("trustStore", trustStore);
File tempSourceDir = Files.createTempDir();
File inputFile = File.createTempFile("smile-unit-test", ".json", tempSourceDir);
try (FileWriter inputFileWriter = new FileWriter(inputFile, StandardCharsets.UTF_8, false)) {
IOUtils.write(json.toString(), inputFileWriter);
}
return inputFile;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,129 @@
package ca.uhn.fhir.test.utilities;
/*-
* #%L
* HAPI FHIR Test Utilities
* %%
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
* %%
* 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.
* #L%
*/
import ca.uhn.fhir.rest.https.KeyStoreInfo;
import ca.uhn.fhir.rest.https.TlsAuthentication;
import ca.uhn.fhir.rest.https.TrustStoreInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import java.io.File;
import java.io.FileWriter;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Optional;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class BaseRequestGeneratingCommandTestUtil implements AfterEachCallback {
private static final String KEYSTORE_RESOURCE_PATH = "/tls/client-keystore.p12";
private static final String KEYSTORE_STOREPASS = "changeit";
private static final String KEYSTORE_KEYPASS = "changeit";
private static final String KEYSTORE_ALIAS = "1";
private static final String TRUSTSTORE_RESOURCE_PATH = "/tls/client-truststore.p12";
private static final String TRUSTSTORE_STOREPASS = "changeit";
private static final String TRUSTSTORE_ALIAS = "client";
private final Optional<TlsAuthentication> myTlsAuthentication;
private final KeyStoreInfo myKeystoreInfo;
private final TrustStoreInfo myTrustStoreInfo;
private File myTempFile;
public BaseRequestGeneratingCommandTestUtil(){
String keyStoreFilePath = BaseRequestGeneratingCommandTestUtil.class.getResource(KEYSTORE_RESOURCE_PATH).getPath();
myKeystoreInfo = new KeyStoreInfo(keyStoreFilePath, KEYSTORE_STOREPASS, KEYSTORE_KEYPASS, KEYSTORE_ALIAS);
String trustStoreFilePath = BaseRequestGeneratingCommandTestUtil.class.getResource(TRUSTSTORE_RESOURCE_PATH).getPath();
myTrustStoreInfo = new TrustStoreInfo(trustStoreFilePath, TRUSTSTORE_STOREPASS, TRUSTSTORE_ALIAS);
myTlsAuthentication = Optional.of(new TlsAuthentication(Optional.of(myKeystoreInfo), Optional.of(myTrustStoreInfo)));
}
@Override
public void afterEach(ExtensionContext theExtensionContext) throws Exception {
if(myTempFile != null && myTempFile.exists()){
assertTrue(myTempFile.delete());
myTempFile = null;
}
}
public String[] createArgs(String[] theBaseArgs, String theUrlFlag, boolean theAddTls, BaseRestServerHelper theRestServerHelper){
if(isBlank(theUrlFlag)){
return theBaseArgs;
}
int newItems = theAddTls ? 4 : 2;
String url = theAddTls ? theRestServerHelper.getSecureBase() : theRestServerHelper.getBase();
int newSize = theBaseArgs.length + newItems;
String[] retVal = Arrays.copyOf(theBaseArgs, newSize);
retVal[newSize - 2] = theUrlFlag;
retVal[newSize - 1] = url;
if(theAddTls){
myTempFile = createTlsAuthenticationFile();
retVal[newSize - 4] = "--tls-auth";
retVal[newSize - 3] = myTempFile.getAbsolutePath();
}
return retVal;
}
public Optional<TlsAuthentication> getTlsAuthentication(){
return myTlsAuthentication;
}
private File createTlsAuthenticationFile() {
try {
ObjectMapper mapper = new ObjectMapper();
ObjectNode keyStore = mapper.createObjectNode();
keyStore.put("filePath", myKeystoreInfo.getFilePath());
keyStore.put("storePass", new String(myKeystoreInfo.getStorePass()));
keyStore.put("keyPass", new String(myKeystoreInfo.getKeyPass()));
keyStore.put("alias", myKeystoreInfo.getAlias());
ObjectNode trustStore = mapper.createObjectNode();
trustStore.put("filePath", myTrustStoreInfo.getFilePath());
trustStore.put("storePass", new String(myTrustStoreInfo.getStorePass()));
ObjectNode json = mapper.createObjectNode();
json.set("keyStore", keyStore);
json.set("trustStore", trustStore);
File inputFile = File.createTempFile("smile-unit-test", ".json");
try (FileWriter inputFileWriter = new FileWriter(inputFile, StandardCharsets.UTF_8, false)) {
IOUtils.write(json.toString(), inputFileWriter);
}
return inputFile;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@ -172,6 +172,8 @@ public abstract class BaseRestServerHelper {
public abstract IResourceProvider getPatientResourceProvider();
public abstract IResourceProvider getConceptMapResourceProvider();
public abstract IIdType createPatientWithId(String theId);
public abstract IIdType createPatient(IBaseResource theBaseResource);

View File

@ -32,6 +32,7 @@ import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import ca.uhn.fhir.rest.server.provider.HashMapResourceProvider;
import ca.uhn.test.concurrency.IPointcutLatch;
import ca.uhn.test.concurrency.PointcutLatch;
import org.hl7.fhir.dstu3.model.ConceptMap;
import org.hl7.fhir.dstu3.model.Observation;
import org.hl7.fhir.dstu3.model.Organization;
import org.hl7.fhir.dstu3.model.Patient;
@ -52,8 +53,19 @@ public class RestServerDstu3Helper extends BaseRestServerHelper implements IPoin
protected final MyRestfulServer myRestServer;
public RestServerDstu3Helper() {
this(false);
}
public RestServerDstu3Helper(boolean theInitialize) {
super(FhirContext.forDstu3());
myRestServer = new MyRestfulServer(myFhirContext);
if(theInitialize){
try {
myRestServer.initialize();
} catch (ServletException e) {
throw new RuntimeException(e);
}
}
}
@Override
@ -191,6 +203,7 @@ public class RestServerDstu3Helper extends BaseRestServerHelper implements IPoin
private HashMapResourceProvider<Patient> myPatientResourceProvider;
private HashMapResourceProvider<Observation> myObservationResourceProvider;
private HashMapResourceProvider<Organization> myOrganizationResourceProvider;
private HashMapResourceProvider<ConceptMap> myConceptMapResourceProvider;
private MyPlainProvider myPlainProvider;
public MyRestfulServer(FhirContext theFhirContext) {
@ -233,6 +246,10 @@ public class RestServerDstu3Helper extends BaseRestServerHelper implements IPoin
return myOrganizationResourceProvider;
}
public HashMapResourceProvider<ConceptMap> getConceptMapResourceProvider() {
return myConceptMapResourceProvider;
}
public HashMapResourceProvider<Patient> getPatientResourceProvider() {
return myPatientResourceProvider;
}
@ -248,11 +265,21 @@ public class RestServerDstu3Helper extends BaseRestServerHelper implements IPoin
registerProvider(myObservationResourceProvider);
myOrganizationResourceProvider = new MyHashMapResourceProvider(fhirContext, Organization.class);
registerProvider(myOrganizationResourceProvider);
myConceptMapResourceProvider = new MyHashMapResourceProvider(fhirContext, ConceptMap.class);
registerProvider(myConceptMapResourceProvider);
myPlainProvider = new MyPlainProvider();
registerProvider(myPlainProvider);
}
public void setConceptMapResourceProvider(HashMapResourceProvider<ConceptMap> theResourceProvider) {
myConceptMapResourceProvider.getStoredResources().forEach(c -> theResourceProvider.store(c));
unregisterProvider(myConceptMapResourceProvider);
registerProvider(theResourceProvider);
myConceptMapResourceProvider = theResourceProvider;
}
public class MyHashMapResourceProvider<T extends IBaseResource> extends HashMapResourceProvider<T> {
public MyHashMapResourceProvider(FhirContext theContext, Class theType) {
@ -279,6 +306,11 @@ public class RestServerDstu3Helper extends BaseRestServerHelper implements IPoin
return myRestServer.getPatientResourceProvider();
}
@Override
public HashMapResourceProvider<ConceptMap> getConceptMapResourceProvider() {
return myRestServer.getConceptMapResourceProvider();
}
@Override
public IIdType createPatientWithId(String theId) {
Patient patient = new Patient();
@ -305,4 +337,8 @@ public class RestServerDstu3Helper extends BaseRestServerHelper implements IPoin
public IIdType createObservation(IBaseResource theBaseResource) {
return myRestServer.getObservationResourceProvider().store((Observation) theBaseResource);
}
public void setConceptMapResourceProvider(HashMapResourceProvider<ConceptMap> theResourceProvider) {
myRestServer.setConceptMapResourceProvider(theResourceProvider);
}
}

View File

@ -34,6 +34,7 @@ import org.eclipse.jetty.server.Request;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.Observation;
import org.hl7.fhir.r4.model.Organization;
import org.hl7.fhir.r4.model.Patient;
@ -58,8 +59,19 @@ public class RestServerR4Helper extends BaseRestServerHelper implements BeforeEa
protected final MyRestfulServer myRestServer;
public RestServerR4Helper() {
this(false);
}
public RestServerR4Helper(boolean theInitialize) {
super(FhirContext.forR4Cached());
myRestServer = new MyRestfulServer(myFhirContext);
if(theInitialize){
try {
myRestServer.initialize();
} catch (ServletException e) {
throw new RuntimeException(e);
}
}
}
@Override
@ -168,6 +180,15 @@ public class RestServerR4Helper extends BaseRestServerHelper implements BeforeEa
return myRestServer.getPatientResourceProvider();
}
@Override
public HashMapResourceProvider<ConceptMap> getConceptMapResourceProvider() {
return myRestServer.getConceptMapResourceProvider();
}
public void setConceptMapResourceProvider(HashMapResourceProvider<ConceptMap> theResourceProvider) {
myRestServer.setConceptMapResourceProvider(theResourceProvider);
}
@Override
public IIdType createPatientWithId(String theId) {
Patient patient = new Patient();
@ -224,6 +245,7 @@ public class RestServerR4Helper extends BaseRestServerHelper implements BeforeEa
private HashMapResourceProvider<Patient> myPatientResourceProvider;
private HashMapResourceProvider<Observation> myObservationResourceProvider;
private HashMapResourceProvider<Organization> myOrganizationResourceProvider;
private HashMapResourceProvider<ConceptMap> myConceptMapResourceProvider;
private RestServerDstu3Helper.MyPlainProvider myPlainProvider;
private final List<String> myRequestUrls = Collections.synchronizedList(new ArrayList<>());
private final List<String> myRequestVerbs = Collections.synchronizedList(new ArrayList<>());
@ -292,6 +314,10 @@ public class RestServerR4Helper extends BaseRestServerHelper implements BeforeEa
return myOrganizationResourceProvider;
}
public HashMapResourceProvider<ConceptMap> getConceptMapResourceProvider() {
return myConceptMapResourceProvider;
}
public HashMapResourceProvider<Patient> getPatientResourceProvider() {
return myPatientResourceProvider;
}
@ -307,6 +333,8 @@ public class RestServerR4Helper extends BaseRestServerHelper implements BeforeEa
registerProvider(myObservationResourceProvider);
myOrganizationResourceProvider = new MyHashMapResourceProvider(fhirContext, Organization.class);
registerProvider(myOrganizationResourceProvider);
myConceptMapResourceProvider = new MyHashMapResourceProvider(fhirContext, ConceptMap.class);
registerProvider(myConceptMapResourceProvider);
myPlainProvider = new RestServerDstu3Helper.MyPlainProvider();
registerProvider(myPlainProvider);
@ -322,6 +350,14 @@ public class RestServerR4Helper extends BaseRestServerHelper implements BeforeEa
myObservationResourceProvider = theResourceProvider;
}
public void setConceptMapResourceProvider(HashMapResourceProvider<ConceptMap> theResourceProvider) {
myConceptMapResourceProvider.getStoredResources().forEach(c -> theResourceProvider.store(c));
unregisterProvider(myConceptMapResourceProvider);
registerProvider(theResourceProvider);
myConceptMapResourceProvider = theResourceProvider;
}
public class MyHashMapResourceProvider<T extends IBaseResource> extends HashMapResourceProvider<T> {
public MyHashMapResourceProvider(FhirContext theContext, Class theType) {