From 9b4b1ae2cc7bec144cf62d7fdd54ebfaa080528f Mon Sep 17 00:00:00 2001 From: dotasek Date: Wed, 19 Apr 2023 17:18:29 -0400 Subject: [PATCH] Add -fhir-settings param to Validator CLI (#1203) * Start work * Tests for new Param * More tests, add param, refactor * Rename + JsonProperty annotations * Logging for API keys * WIP rename search parameter + add settings object for serialization * Switch to JSON based settings file. * Rename FHIRSettings and remove ToolGlobalSettings * Update default path for settings file + expand test * Only allow single instantiation with explicitFilePath * Move and expand tests * Fix failing test * Add test for FhirSettings param precedence * Refactor to only call getInstance() internally in FhirSettings --- .../fhir/dstu2/utils/client/ClientUtils.java | 27 +-- .../client/network/FhirRequestBuilder.java | 5 +- .../fhir/r4/test/utils/TestingUtilities.java | 11 +- .../client/network/FhirRequestBuilder.java | 5 +- .../fhir/r5/test/utils/CompareUtilities.java | 9 +- .../client/network/FhirRequestBuilder.java | 4 +- .../org/hl7/fhir/utilities/FTPClient.java | 3 +- .../org/hl7/fhir/utilities/PathBuilder.java | 5 +- .../hl7/fhir/utilities/SimpleHTTPClient.java | 7 +- .../fhir/utilities/ToolGlobalSettings.java | 101 ---------- .../fhir/utilities/settings/FhirSettings.java | 176 ++++++++++++++++++ .../utilities/settings/FhirSettingsPOJO.java | 42 +++++ .../utilities/tests/BaseTestingUtilities.java | 24 ++- .../org/hl7/fhir/utilities/UtilitiesTest.java | 5 +- .../utilities/settings/FhirSettingsTests.java | 87 +++++++++ .../resources/settings/settings-example.json | 15 ++ .../hl7/fhir/validation/ValidationEngine.java | 10 +- .../org/hl7/fhir/validation/ValidatorCli.java | 6 + .../fhir/validation/cli/model/CliContext.java | 14 ++ .../cli/services/ValidationService.java | 129 +++++++------ .../hl7/fhir/validation/cli/utils/Params.java | 7 + .../cli/services/ValidationServiceTest.java | 56 +++++- .../validation/cli/utils/ParamsTests.java | 23 +++ .../org.hl7.fhir.validation/1.0.2/loinc.cache | 11 ++ .../1.0.2/snomed.cache | 11 ++ .../org.hl7.fhir.validation/1.0.2/ucum.cache | 10 + 26 files changed, 582 insertions(+), 221 deletions(-) delete mode 100644 org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/ToolGlobalSettings.java create mode 100644 org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/settings/FhirSettings.java create mode 100644 org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/settings/FhirSettingsPOJO.java create mode 100644 org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/settings/FhirSettingsTests.java create mode 100644 org.hl7.fhir.utilities/src/test/resources/settings/settings-example.json diff --git a/org.hl7.fhir.dstu2/src/main/java/org/hl7/fhir/dstu2/utils/client/ClientUtils.java b/org.hl7.fhir.dstu2/src/main/java/org/hl7/fhir/dstu2/utils/client/ClientUtils.java index 26dae9744..9e54e6a21 100644 --- a/org.hl7.fhir.dstu2/src/main/java/org/hl7/fhir/dstu2/utils/client/ClientUtils.java +++ b/org.hl7.fhir.dstu2/src/main/java/org/hl7/fhir/dstu2/utils/client/ClientUtils.java @@ -86,9 +86,10 @@ import org.hl7.fhir.dstu2.model.Resource; import org.hl7.fhir.dstu2.model.ResourceType; import org.hl7.fhir.dstu2.utils.ResourceUtilities; import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.utilities.ToolGlobalSettings; + import org.hl7.fhir.utilities.ToolingClientLogger; import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.utilities.settings.FhirSettings; /** * Helper class handling lower level HTTP transport concerns. @@ -142,7 +143,7 @@ public class ClientUtils { } public ResourceRequest issueOptionsRequest(URI optionsUri, String resourceFormat, int timeoutLoading) { - if (ToolGlobalSettings.isNoNetwork()) { + if (FhirSettings.isProhibitNetworkAccess()) { throw new FHIRException("Network Access is prohibited in this context"); } @@ -151,7 +152,7 @@ public class ClientUtils { } public ResourceRequest issueGetResourceRequest(URI resourceUri, String resourceFormat, int timeoutLoading) { - if (ToolGlobalSettings.isNoNetwork()) { + if (FhirSettings.isProhibitNetworkAccess()) { throw new FHIRException("Network Access is prohibited in this context"); } HttpGet httpget = new HttpGet(resourceUri); @@ -159,7 +160,7 @@ public class ClientUtils { } public ResourceRequest issuePutRequest(URI resourceUri, byte[] payload, String resourceFormat, List
headers, int timeoutLoading) { - if (ToolGlobalSettings.isNoNetwork()) { + if (FhirSettings.isProhibitNetworkAccess()) { throw new FHIRException("Network Access is prohibited in this context"); } HttpPut httpPut = new HttpPut(resourceUri); @@ -167,7 +168,7 @@ public class ClientUtils { } public ResourceRequest issuePutRequest(URI resourceUri, byte[] payload, String resourceFormat, int timeoutLoading) { - if (ToolGlobalSettings.isNoNetwork()) { + if (FhirSettings.isProhibitNetworkAccess()) { throw new FHIRException("Network Access is prohibited in this context"); } HttpPut httpPut = new HttpPut(resourceUri); @@ -175,7 +176,7 @@ public class ClientUtils { } public ResourceRequest issuePostRequest(URI resourceUri, byte[] payload, String resourceFormat, List
headers, int timeoutLoading) { - if (ToolGlobalSettings.isNoNetwork()) { + if (FhirSettings.isProhibitNetworkAccess()) { throw new FHIRException("Network Access is prohibited in this context"); } HttpPost httpPost = new HttpPost(resourceUri); @@ -188,7 +189,7 @@ public class ClientUtils { } public Bundle issueGetFeedRequest(URI resourceUri, String resourceFormat) { - if (ToolGlobalSettings.isNoNetwork()) { + if (FhirSettings.isProhibitNetworkAccess()) { throw new FHIRException("Network Access is prohibited in this context"); } HttpGet httpget = new HttpGet(resourceUri); @@ -209,7 +210,7 @@ public class ClientUtils { } public Bundle postBatchRequest(URI resourceUri, byte[] payload, String resourceFormat, int timeoutLoading) { - if (ToolGlobalSettings.isNoNetwork()) { + if (FhirSettings.isProhibitNetworkAccess()) { throw new FHIRException("Network Access is prohibited in this context"); } HttpPost httpPost = new HttpPost(resourceUri); @@ -219,7 +220,7 @@ public class ClientUtils { } public boolean issueDeleteRequest(URI resourceUri) { - if (ToolGlobalSettings.isNoNetwork()) { + if (FhirSettings.isProhibitNetworkAccess()) { throw new FHIRException("Network Access is prohibited in this context"); } HttpDelete deleteRequest = new HttpDelete(resourceUri); @@ -255,7 +256,7 @@ public class ClientUtils { * @return */ protected ResourceRequest issueResourceRequest(String resourceFormat, HttpUriRequest request, byte[] payload, List
headers, int timeoutLoading) { - if (ToolGlobalSettings.isNoNetwork()) { + if (FhirSettings.isProhibitNetworkAccess()) { throw new FHIRException("Network Access is prohibited in this context"); } configureFhirRequest(request, resourceFormat, headers); @@ -315,7 +316,7 @@ public class ClientUtils { */ @SuppressWarnings({ "resource", "deprecation" }) protected HttpResponse sendPayload(HttpEntityEnclosingRequestBase request, byte[] payload, HttpHost proxy, int timeoutLoading) { - if (ToolGlobalSettings.isNoNetwork()) { + if (FhirSettings.isProhibitNetworkAccess()) { throw new FHIRException("Network Access is prohibited in this context"); } HttpResponse response = null; @@ -356,7 +357,7 @@ public class ClientUtils { * @return */ protected HttpResponse sendRequest(HttpUriRequest request) { - if (ToolGlobalSettings.isNoNetwork()) { + if (FhirSettings.isProhibitNetworkAccess()) { throw new FHIRException("Network Access is prohibited in this context"); } HttpResponse response = null; @@ -466,7 +467,7 @@ public class ClientUtils { * ***************************************************************/ public HttpURLConnection buildConnection(URI baseServiceUri, String tail) { - if (ToolGlobalSettings.isNoNetwork()) { + if (FhirSettings.isProhibitNetworkAccess()) { throw new FHIRException("Network Access is prohibited in this context"); } diff --git a/org.hl7.fhir.dstu3/src/main/java/org/hl7/fhir/dstu3/utils/client/network/FhirRequestBuilder.java b/org.hl7.fhir.dstu3/src/main/java/org/hl7/fhir/dstu3/utils/client/network/FhirRequestBuilder.java index fe4a4f5d8..9396ca6c2 100644 --- a/org.hl7.fhir.dstu3/src/main/java/org/hl7/fhir/dstu3/utils/client/network/FhirRequestBuilder.java +++ b/org.hl7.fhir.dstu3/src/main/java/org/hl7/fhir/dstu3/utils/client/network/FhirRequestBuilder.java @@ -12,8 +12,9 @@ import org.hl7.fhir.dstu3.utils.ResourceUtilities; import org.hl7.fhir.dstu3.utils.client.EFhirClientException; import org.hl7.fhir.dstu3.utils.client.ResourceFormat; import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.utilities.ToolGlobalSettings; + import org.hl7.fhir.utilities.ToolingClientLogger; +import org.hl7.fhir.utilities.settings.FhirSettings; import javax.annotation.Nonnull; import java.io.IOException; @@ -152,7 +153,7 @@ public class FhirRequestBuilder { * @return {@link OkHttpClient} instance */ protected OkHttpClient getHttpClient() { - if (ToolGlobalSettings.isNoNetwork()) { + if (FhirSettings.isProhibitNetworkAccess()) { throw new FHIRException("Network Access is prohibited in this context"); } diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/test/utils/TestingUtilities.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/test/utils/TestingUtilities.java index 3af459ca4..e92894770 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/test/utils/TestingUtilities.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/test/utils/TestingUtilities.java @@ -51,12 +51,9 @@ import org.fhir.ucum.UcumEssenceService; import org.hl7.fhir.r4.context.IWorkerContext; import org.hl7.fhir.r4.context.SimpleWorkerContext; import org.hl7.fhir.r4.model.Parameters; -import org.hl7.fhir.utilities.CSFile; -import org.hl7.fhir.utilities.TextFile; -import org.hl7.fhir.utilities.ToolGlobalSettings; -import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.utilities.*; import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.npm.ToolsVersion; +import org.hl7.fhir.utilities.settings.FhirSettings; import org.hl7.fhir.utilities.tests.BaseTestingUtilities; import org.hl7.fhir.utilities.tests.ResourceLoaderTests; import org.hl7.fhir.utilities.tests.TestConfig; @@ -490,8 +487,8 @@ public class TestingUtilities { */ String dir = TestConfig.getInstance().getFhirTestCasesDirectory(); - if (dir == null && ToolGlobalSettings.hasTestsPath()) { - dir = ToolGlobalSettings.getTestsPath(); + if (dir == null && FhirSettings.hasFhirTestCasesPath()) { + dir = FhirSettings.getFhirTestCasesPath(); } if (dir != null && new CSFile(dir).exists()) { String n = Utilities.path(dir, Utilities.path(paths)); diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/client/network/FhirRequestBuilder.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/client/network/FhirRequestBuilder.java index ccbea84d2..72066dcb8 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/client/network/FhirRequestBuilder.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/client/network/FhirRequestBuilder.java @@ -12,7 +12,8 @@ import org.hl7.fhir.r4.model.Resource; import org.hl7.fhir.r4.utils.ResourceUtilities; import org.hl7.fhir.r4.utils.client.EFhirClientException; import org.hl7.fhir.r4.utils.client.ResourceFormat; -import org.hl7.fhir.utilities.ToolGlobalSettings; +import org.hl7.fhir.utilities.settings.FhirSettings; + import javax.annotation.Nonnull; import java.io.IOException; @@ -150,7 +151,7 @@ public class FhirRequestBuilder { * @return {@link OkHttpClient} instance */ protected OkHttpClient getHttpClient() { - if (ToolGlobalSettings.isNoNetwork()) { + if (FhirSettings.isProhibitNetworkAccess()) { throw new FHIRException("Network Access is prohibited in this context"); } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/test/utils/CompareUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/test/utils/CompareUtilities.java index e9bd3c532..40d1219ce 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/test/utils/CompareUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/test/utils/CompareUtilities.java @@ -2,12 +2,9 @@ package org.hl7.fhir.r5.test.utils; import org.apache.commons.codec.binary.Base64; import org.apache.commons.lang3.StringUtils; -import org.hl7.fhir.r5.model.ValueSet; -import org.hl7.fhir.utilities.CSFile; -import org.hl7.fhir.utilities.TextFile; -import org.hl7.fhir.utilities.ToolGlobalSettings; -import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.utilities.*; +import org.hl7.fhir.utilities.settings.FhirSettings; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; @@ -47,7 +44,7 @@ public class CompareUtilities extends BaseTestingUtilities { public static String checkXMLIsSame(String expected, String actual) throws Exception { String result = compareXml(expected, actual); if (result != null && SHOW_DIFF) { - String diff = ToolGlobalSettings.hasComparePath() ? ToolGlobalSettings.getComparePath() : Utilities.path(System.getenv("ProgramFiles"), "WinMerge", "WinMergeU.exe"); + String diff = FhirSettings.hasDiffToolPath() ? FhirSettings.getDiffToolPath() : Utilities.path(System.getenv("ProgramFiles"), "WinMerge", "WinMergeU.exe"); if (new File(diff).exists() || Utilities.isToken(diff)) { Runtime.getRuntime().exec(new String[]{diff, expected, actual}); } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/client/network/FhirRequestBuilder.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/client/network/FhirRequestBuilder.java index d7db0af63..315a26d23 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/client/network/FhirRequestBuilder.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/client/network/FhirRequestBuilder.java @@ -12,7 +12,7 @@ import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.utils.ResourceUtilities; import org.hl7.fhir.r5.utils.client.EFhirClientException; import org.hl7.fhir.r5.utils.client.ResourceFormat; -import org.hl7.fhir.utilities.ToolGlobalSettings; +import org.hl7.fhir.utilities.settings.FhirSettings; import javax.annotation.Nonnull; import java.io.IOException; @@ -150,7 +150,7 @@ public class FhirRequestBuilder { * @return {@link OkHttpClient} instance */ protected OkHttpClient getHttpClient() { - if (ToolGlobalSettings.isNoNetwork()) { + if (FhirSettings.isProhibitNetworkAccess()) { throw new FHIRException("Network Access is prohibited in this context"); } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/FTPClient.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/FTPClient.java index 879331693..544a6b87f 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/FTPClient.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/FTPClient.java @@ -6,6 +6,7 @@ import lombok.Getter; import org.apache.commons.net.ftp.FTP; import org.apache.commons.net.ftp.FTPReply; import org.hl7.fhir.exceptions.FHIRException; +import org.hl7.fhir.utilities.settings.FhirSettings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -100,7 +101,7 @@ public class FTPClient { * Connect to the server, throw an exception if it fails */ public void connect() throws IOException { - if (ToolGlobalSettings.isNoNetwork()) { + if (FhirSettings.isProhibitNetworkAccess()) { throw new FHIRException("Network Access is prohibited in this context"); } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/PathBuilder.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/PathBuilder.java index a063bf93c..6abb47a10 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/PathBuilder.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/PathBuilder.java @@ -3,6 +3,7 @@ package org.hl7.fhir.utilities; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.With; +import org.hl7.fhir.utilities.settings.FhirSettings; import java.io.File; import java.nio.file.Path; @@ -166,8 +167,8 @@ public class PathBuilder { if ("[tmp]".equals(a)) { if (hasCTempDir()) { return Utilities.C_TEMP_DIR; - } else if (ToolGlobalSettings.hasTempPath()) { - return ToolGlobalSettings.getTempPath(); + } else if (FhirSettings.hasTempPath()) { + return FhirSettings.getTempPath(); } else { return System.getProperty("java.io.tmpdir"); } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/SimpleHTTPClient.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/SimpleHTTPClient.java index 6c016d7e5..95cb1bba6 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/SimpleHTTPClient.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/SimpleHTTPClient.java @@ -16,6 +16,7 @@ import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.utilities.SimpleHTTPClient.HTTPResult; import org.hl7.fhir.utilities.SimpleHTTPClient.Header; import org.hl7.fhir.utilities.npm.SSLCertTruster; +import org.hl7.fhir.utilities.settings.FhirSettings; public class SimpleHTTPClient { @@ -123,7 +124,7 @@ public class SimpleHTTPClient { } public HTTPResult get(String url, String accept) throws IOException { - if (ToolGlobalSettings.isNoNetwork()) { + if (FhirSettings.isProhibitNetworkAccess()) { throw new FHIRException("Network Access is prohibited in this context"); } @@ -185,7 +186,7 @@ public class SimpleHTTPClient { } public HTTPResult post(String url, String contentType, byte[] content, String accept) throws IOException { - if (ToolGlobalSettings.isNoNetwork()) { + if (FhirSettings.isProhibitNetworkAccess()) { throw new FHIRException("Network Access is prohibited in this context"); } URL u = new URL(url); @@ -205,7 +206,7 @@ public class SimpleHTTPClient { public HTTPResult put(String url, String contentType, byte[] content, String accept) throws IOException { - if (ToolGlobalSettings.isNoNetwork()) { + if (FhirSettings.isProhibitNetworkAccess()) { throw new FHIRException("Network Access is prohibited in this context"); } URL u = new URL(url); diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/ToolGlobalSettings.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/ToolGlobalSettings.java deleted file mode 100644 index bdf677591..000000000 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/ToolGlobalSettings.java +++ /dev/null @@ -1,101 +0,0 @@ -package org.hl7.fhir.utilities; - -import java.io.IOException; - -public class ToolGlobalSettings { - - private static Boolean noNetwork = null; - private static boolean inited = false; - - private static String npmPath; - private static String rubyPath; - private static String testsPath; - private static String comparePath; - private static String tempPath; - private static String testIgsPath; - - public static String getNpmPath() { - init(); - return npmPath; - } - public static String getRubyPath() { - init(); - return rubyPath; - } - public static String getTestsPath() { - init(); - return testsPath; - } - - public static boolean hasNpmPath() { - init(); - return npmPath != null; - } - - public static boolean hasRubyPath() { - init(); - return rubyPath != null; - } - public static boolean hasTestsPath() { - init(); - return testsPath != null; - } - - public static String getComparePath() { - init(); - return comparePath; - } - public static boolean hasComparePath() { - init(); - return comparePath != null; - } - - public static String getTempPath() { - init(); - return tempPath; - } - public static boolean hasTempPath() { - init(); - return tempPath != null; - } - - public static String getTestIgsPath() { - init(); - return testIgsPath; - } - public static boolean hasTestIgsPath() { - init(); - return testIgsPath != null; - } - - - public static boolean isNoNetwork() { - init(); - return noNetwork == null ? false : noNetwork; - } - - public static void setNoNetwork(boolean value) { - init(); - noNetwork = value; - } - - private static void init() { - if (!inited) { - inited = true; - IniFile ini; - try { - ini = new IniFile(Utilities.path(Utilities.path(System.getProperty("user.home"), ".fhir", "fhir-tool-settings.conf"))); - if (ini.hasSection("paths")) { - npmPath = ini.getStringProperty("paths", "npm"); - rubyPath = ini.getStringProperty("paths", "ruby"); - testsPath = ini.getStringProperty("paths", "tests"); - comparePath = ini.getStringProperty("paths", "compare"); - tempPath = ini.getStringProperty("paths", "temp"); - testIgsPath = ini.getStringProperty("paths", "test-igs"); - noNetwork = ini.getBooleanProperty("network", "no-access"); - } - } catch (IOException e) { - } - } - } -} \ No newline at end of file diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/settings/FhirSettings.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/settings/FhirSettings.java new file mode 100644 index 000000000..73a14f900 --- /dev/null +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/settings/FhirSettings.java @@ -0,0 +1,176 @@ +package org.hl7.fhir.utilities.settings; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.Getter; +import org.hl7.fhir.utilities.Utilities; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + + + +public class FhirSettings { + + public static final String FHIR_SETTINGS_PATH = "fhir.settings.path"; + private static String explicitFilePath = null; + + public static void setExplicitFilePath(String explicitFilePath) { + if (instance != null) { + throw new IllegalStateException("Attempted to set explicitFilePath after FhirSettings has already been initialized with path: " + instance.filePath); + } + if (FhirSettings.explicitFilePath != null) { + throw new IllegalStateException("Attempted to set explicitFilePath to " + explicitFilePath + " when already set to " + FhirSettings.explicitFilePath); + } + FhirSettings.explicitFilePath = explicitFilePath; + } + private final FhirSettingsPOJO fhirSettings; + + public static String getFilePath() { + getInstance(); + return instance.filePath; + } + + final String filePath; + private FhirSettings(FhirSettingsPOJO fhirSettings, String filePath) { + + this.fhirSettings = fhirSettings; + this.filePath = filePath; + } + + public static String getApiKey(String key) { + getInstance(); + return instance.fhirSettings.getApiKeys() != null + ? instance.fhirSettings.getApiKeys().get(key) + : null; + } + + public static boolean hasApiKey(String key) { + getInstance(); + return instance.fhirSettings.getApiKeys() != null + ? instance.fhirSettings.getApiKeys().get(key) != null + : null; + } + + public static String getNpmPath() { + getInstance(); + return instance.fhirSettings.getNpmPath(); + } + + public static boolean hasNpmPath() { + getInstance(); + return instance.fhirSettings.getNpmPath() != null; + } + public static boolean hasRubyPath() { + getInstance(); + return instance.fhirSettings.getRubyPath() != null; + } + + public static String getRubyPath() { + getInstance(); + return instance.fhirSettings.getRubyPath(); + } + + public static boolean hasFhirTestCasesPath() { + getInstance(); + return instance.fhirSettings.getFhirTestCasesPath() != null; + } + + public static String getFhirTestCasesPath() { + getInstance(); + return instance.fhirSettings.getFhirTestCasesPath(); + } + + public static boolean hasDiffToolPath() { + getInstance(); + return instance.fhirSettings.getDiffToolPath() != null; + } + + public static String getDiffToolPath() { + getInstance(); + return instance.fhirSettings.getDiffToolPath(); + } + + public static boolean hasTempPath() { + getInstance(); + return instance.fhirSettings.getTempPath() != null; + } + + public static String getTempPath() { + getInstance(); + return instance.fhirSettings.getTempPath(); + } + + public static boolean hasTestIGsPath() { + getInstance(); + return instance.fhirSettings.getTestIgsPath() != null; + } + + public static String getTestIgsPath() { + getInstance(); + return instance.fhirSettings.getTestIgsPath(); + } + + public static boolean hasProhibitNetworkAccess() { + getInstance(); + return instance.fhirSettings.getProhibitNetworkAccess() != null; } + + public static boolean isProhibitNetworkAccess() { + getInstance(); + return instance.fhirSettings.getProhibitNetworkAccess() == null + ? false + : instance.fhirSettings.getProhibitNetworkAccess(); } + private static FhirSettings instance = null; + + private static FhirSettings getInstance() { + if (instance == null) { + try { + instance = getInstanceFromPath(explicitFilePath); + } catch (IOException e) { + e.printStackTrace(); + instance = new FhirSettings(new FhirSettingsPOJO(), null); + } + } + return instance; + } + + protected static FhirSettings getInstanceFromPath(String explicitFilePath) throws IOException { + final String filePath; + filePath = getSettingsFilePath(explicitFilePath); + return new FhirSettings(getFhirSettingsPOJO(filePath), filePath); + } + + protected static String getSettingsFilePath(String explicitFilePath) { + final String filePath; + String pathFromSystemProperties; + try { + pathFromSystemProperties = getDefaultSettingsPath(); + } catch (IOException e) { + pathFromSystemProperties = null; + } + filePath = explicitFilePath != null ? explicitFilePath : + System.getProperty(FHIR_SETTINGS_PATH, pathFromSystemProperties); + return filePath; + } + + static FhirSettingsPOJO getFhirSettingsPOJO(String filePath) throws IOException { + final File file = new File(filePath); + + if (!file.exists()) { + return new FhirSettingsPOJO(); + } + + final ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + final InputStream inputStream = new FileInputStream(file); + final FhirSettingsPOJO output = objectMapper.readValue(inputStream, FhirSettingsPOJO.class); + + return output; + } + + protected static String getDefaultSettingsPath() throws IOException { + return Utilities.path(System.getProperty("user.home"), ".fhir", "fhir-settings.json"); + } +} diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/settings/FhirSettingsPOJO.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/settings/FhirSettingsPOJO.java new file mode 100644 index 000000000..72a832984 --- /dev/null +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/settings/FhirSettingsPOJO.java @@ -0,0 +1,42 @@ +package org.hl7.fhir.utilities.settings; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.extern.jackson.Jacksonized; + +import java.util.Map; + +@Data +@Builder +@Jacksonized +@AllArgsConstructor +public class FhirSettingsPOJO { + + private String fhirDirectory; + private Map apiKeys; + + private String npmPath; + + private String rubyPath; + + private String fhirTestCasesPath; + + private String diffToolPath; + + private String tempPath; + + private String testIgsPath; + + private Boolean prohibitNetworkAccess; + + protected FhirSettingsPOJO() { + apiKeys = null; + npmPath = null; + rubyPath = null; + fhirTestCasesPath = null; + diffToolPath = null; + tempPath = null; + testIgsPath = null; + } +} diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/tests/BaseTestingUtilities.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/tests/BaseTestingUtilities.java index af1d22901..a928146c5 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/tests/BaseTestingUtilities.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/tests/BaseTestingUtilities.java @@ -1,10 +1,8 @@ package org.hl7.fhir.utilities.tests; import org.apache.commons.io.IOUtils; -import org.hl7.fhir.utilities.CSFile; -import org.hl7.fhir.utilities.TextFile; -import org.hl7.fhir.utilities.ToolGlobalSettings; -import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.utilities.*; +import org.hl7.fhir.utilities.settings.FhirSettings; import java.io.*; import java.nio.file.Path; @@ -25,8 +23,8 @@ public class BaseTestingUtilities { */ String dir = TestConfig.getInstance().getFhirTestCasesDirectory(); - if (dir == null && ToolGlobalSettings.hasTestsPath()) { - dir = ToolGlobalSettings.getTestsPath(); + if (dir == null && FhirSettings.hasFhirTestCasesPath()) { + dir = FhirSettings.getFhirTestCasesPath(); } if (dir != null && new CSFile(dir).exists()) { String n = Utilities.path(dir, Utilities.path(paths)); @@ -49,8 +47,8 @@ public class BaseTestingUtilities { public static InputStream loadTestResourceStream(String... paths) throws IOException { String dir = TestConfig.getInstance().getFhirTestCasesDirectory(); - if (dir == null && ToolGlobalSettings.hasTestsPath()) { - dir = ToolGlobalSettings.getTestsPath(); + if (dir == null && FhirSettings.hasFhirTestCasesPath()) { + dir = FhirSettings.getFhirTestCasesPath(); } if (dir != null && new File(dir).exists()) { String n = Utilities.path(dir, Utilities.path(paths)); @@ -67,8 +65,8 @@ public class BaseTestingUtilities { public static byte[] loadTestResourceBytes(String... paths) throws IOException { String dir = TestConfig.getInstance().getFhirTestCasesDirectory(); - if (dir == null && ToolGlobalSettings.hasTestsPath()) { - dir = ToolGlobalSettings.getTestsPath(); + if (dir == null && FhirSettings.hasFhirTestCasesPath()) { + dir = FhirSettings.getFhirTestCasesPath(); } if (dir != null && new File(dir).exists()) { String n = Utilities.path(dir, Utilities.path(paths)); @@ -85,8 +83,8 @@ public class BaseTestingUtilities { public static boolean findTestResource(String... paths) throws IOException { String dir = TestConfig.getInstance().getFhirTestCasesDirectory(); - if (dir == null && ToolGlobalSettings.hasTestsPath()) { - dir = ToolGlobalSettings.getTestsPath(); + if (dir == null && FhirSettings.hasFhirTestCasesPath()) { + dir = FhirSettings.getFhirTestCasesPath(); } if (dir != null && new File(dir).exists()) { String n = Utilities.path(dir, Utilities.path(paths)); @@ -108,7 +106,7 @@ public class BaseTestingUtilities { } public static String tempFolder(String name) throws IOException { - String path = Utilities.path(ToolGlobalSettings.hasTempPath() ? ToolGlobalSettings.getTempPath() : "[tmp]", name); + String path = Utilities.path(FhirSettings.hasTempPath() ? FhirSettings.getTempPath() : "[tmp]", name); Utilities.createDirectory(path); return path; } diff --git a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/UtilitiesTest.java b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/UtilitiesTest.java index ae5e5e722..724165e8d 100644 --- a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/UtilitiesTest.java +++ b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/UtilitiesTest.java @@ -11,6 +11,7 @@ import java.util.Random; import java.util.stream.Stream; import org.apache.commons.lang3.SystemUtils; +import org.hl7.fhir.utilities.settings.FhirSettings; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -45,8 +46,8 @@ class UtilitiesTest { @Test @DisplayName("Test Utilities.path maps temp directory correctly") public void testTempDirPath() throws IOException { - if (ToolGlobalSettings.hasTempPath()) { - assertEquals(Utilities.path("[tmp]", TEST_TXT), ToolGlobalSettings.getTempPath() +File.separator+ TEST_TXT); + if (FhirSettings.hasTempPath()) { + assertEquals(Utilities.path("[tmp]", TEST_TXT), FhirSettings.getTempPath() +File.separator+ TEST_TXT); } else { assertEquals(Utilities.path("[tmp]", TEST_TXT), getTempDirectory() + TEST_TXT); } diff --git a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/settings/FhirSettingsTests.java b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/settings/FhirSettingsTests.java new file mode 100644 index 000000000..61f37e2cf --- /dev/null +++ b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/settings/FhirSettingsTests.java @@ -0,0 +1,87 @@ +package org.hl7.fhir.utilities.settings; + +import org.hl7.fhir.utilities.tests.ResourceLoaderTests; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.parallel.Isolated; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@Isolated +public class FhirSettingsTests implements ResourceLoaderTests { + + private static String existingFhirSettingsPath; + + @BeforeAll + public static void beforeAll() { + existingFhirSettingsPath = System.getProperty(FhirSettings.FHIR_SETTINGS_PATH); + System.clearProperty(FhirSettings.FHIR_SETTINGS_PATH); + } + + @AfterEach + public void afterEach() { + System.clearProperty(FhirSettings.FHIR_SETTINGS_PATH); + } + + @AfterAll + public static void afterAll() { + if (existingFhirSettingsPath == null) { + System.clearProperty(FhirSettings.FHIR_SETTINGS_PATH); + } else { + System.setProperty(FhirSettings.FHIR_SETTINGS_PATH, existingFhirSettingsPath); + } + } + + @Test + public void testDefaultFhirSettingsPath() throws IOException { + String actualPath = FhirSettings.getSettingsFilePath(null); + assertEquals(FhirSettings.getDefaultSettingsPath(), actualPath); + } + + @Test + public void testJavaSystemPropertyFhirSettingsPath() throws IOException { + final String dummyPath = "dummy-path"; + System.setProperty(FhirSettings.FHIR_SETTINGS_PATH, dummyPath); + String actualPath = FhirSettings.getSettingsFilePath(null); + assertEquals(dummyPath, actualPath); + } + + @Test + public void testExplicitSettingsPathSelected() throws IOException { + final String wrongDummyPath = "wrong-dummy-path"; + final String dummyPath = "dummy-path"; + System.setProperty(FhirSettings.FHIR_SETTINGS_PATH, wrongDummyPath); + String actualPath = FhirSettings.getSettingsFilePath(dummyPath); + assertEquals(dummyPath, actualPath); + } + + @Test + public void testExplicitFhirSettingsPath() throws IOException { + final String dummyPath = "dummy-path"; + String actualPath = FhirSettings.getSettingsFilePath(dummyPath); + assertEquals(dummyPath, actualPath); + } + + @Test + public void testParseFhirSettings() throws IOException { + Path path = Files.createTempFile("fhir-settings", "json").toAbsolutePath(); + copyResourceToFile(path, "settings", "settings-example.json"); + + FhirSettingsPOJO fhirSettings = FhirSettings.getFhirSettingsPOJO(path.toString()); + + assertEquals("dummy-npm-path", fhirSettings.getNpmPath()); + assertEquals("dummy-ruby-path", fhirSettings.getRubyPath()); + assertEquals("dummy-api-key-value", fhirSettings.getApiKeys().get("dummy-api-key")); + assertEquals("dummy-fhir-test-cases-path", fhirSettings.getFhirTestCasesPath()); + assertEquals("dummy-diff-tool-path", fhirSettings.getDiffToolPath()); + assertEquals("dummy-temp-path", fhirSettings.getTempPath()); + assertEquals("dummy-test-igs-path", fhirSettings.getTestIgsPath()); + } +} diff --git a/org.hl7.fhir.utilities/src/test/resources/settings/settings-example.json b/org.hl7.fhir.utilities/src/test/resources/settings/settings-example.json new file mode 100644 index 000000000..514155e46 --- /dev/null +++ b/org.hl7.fhir.utilities/src/test/resources/settings/settings-example.json @@ -0,0 +1,15 @@ +{ + "apiKeys": { + "dummy-api-key": "dummy-api-key-value" + }, + "npmPath": "dummy-npm-path", + "rubyPath": "dummy-ruby-path", + "fhirTestCasesPath": "dummy-fhir-test-cases-path", + "diffToolPath": "dummy-diff-tool-path", + "tempPath": "dummy-temp-path", + "testIgsPath": "dummy-test-igs-path", + "unusedField" : "unused", + "unusedData" : { + "unusedDateField" : "unused-data" + } +} \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java index febd27a55..40851c583 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java @@ -77,19 +77,13 @@ import org.hl7.fhir.r5.utils.validation.constants.CodedContentValidationPolicy; import org.hl7.fhir.r5.utils.validation.constants.ContainedReferenceValidationPolicy; import org.hl7.fhir.r5.utils.validation.constants.IdStatus; import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy; -import org.hl7.fhir.utilities.FhirPublication; -import org.hl7.fhir.utilities.IniFile; -import org.hl7.fhir.utilities.SIDUtilities; -import org.hl7.fhir.utilities.SimpleHTTPClient; +import org.hl7.fhir.utilities.*; import org.hl7.fhir.utilities.SimpleHTTPClient.HTTPResult; -import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.TimeTracker; -import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.npm.CommonPackages; import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; import org.hl7.fhir.utilities.npm.NpmPackage; -import org.hl7.fhir.utilities.npm.ToolsVersion; +import org.hl7.fhir.utilities.settings.FhirSettings; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.xhtml.XhtmlComposer; import org.hl7.fhir.validation.BaseValidator.ValidationControl; diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidatorCli.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidatorCli.java index 92476f49f..3b1f618a9 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidatorCli.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidatorCli.java @@ -78,6 +78,7 @@ import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.json.JsonException; import org.hl7.fhir.utilities.npm.CommonPackages; +import org.hl7.fhir.utilities.settings.FhirSettings; import org.hl7.fhir.validation.cli.model.CliContext; import org.hl7.fhir.validation.cli.services.ComparisonService; import org.hl7.fhir.validation.cli.services.ValidationService; @@ -130,6 +131,11 @@ public class ValidatorCli { Display.displaySystemInfo(); CliContext cliContext = Params.loadCliContext(args); + + if (cliContext.getFhirSettingsFile() != null) { + FhirSettings.setExplicitFilePath(cliContext.getFhirSettingsFile()); + } + FileFormat.checkCharsetAndWarnIfNotUTF8(System.out); if (shouldDisplayHelpToUser(args)) { diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/model/CliContext.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/model/CliContext.java index a470f07a2..176c3640e 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/model/CliContext.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/model/CliContext.java @@ -131,6 +131,9 @@ public class CliContext { @JsonProperty("tgtLang") private String tgtLang = null; + @JsonProperty("fhirSettingsFile") + private String fhirSettingsFile; + @JsonProperty("map") public String getMap() { @@ -768,4 +771,15 @@ public class CliContext { ", bundleValidationRules=" + bundleValidationRules + '}'; } + + @JsonProperty("fhirSettingsFile") + public CliContext setFhirSettingsFile(String fhirSettingsFile) { + this.fhirSettingsFile = fhirSettingsFile; + return this; + } + + @JsonProperty("fhirSettingsFile") + public String getFhirSettingsFile() { + return fhirSettingsFile; + } } \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/ValidationService.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/ValidationService.java index 59481a733..9a490a8a0 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/ValidationService.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/ValidationService.java @@ -7,6 +7,7 @@ import java.io.IOException; import java.io.PrintStream; import java.lang.management.ManagementFactory; import java.lang.management.MemoryMXBean; +import java.net.URISyntaxException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; @@ -50,7 +51,7 @@ import org.hl7.fhir.utilities.i18n.LanguageFileProducer.LanguageProducerSession; import org.hl7.fhir.utilities.i18n.PoGetTextProducer; import org.hl7.fhir.utilities.i18n.XLIFFProducer; import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.npm.ToolsVersion; +import org.hl7.fhir.utilities.settings.FhirSettings; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.validation.Content; import org.hl7.fhir.validation.IgLoader; @@ -71,6 +72,8 @@ import org.hl7.fhir.validation.cli.renderers.ValidationOutputRenderer; import org.hl7.fhir.validation.cli.utils.EngineMode; import org.hl7.fhir.validation.cli.utils.VersionSourceInformation; +import javax.annotation.Nonnull; + public class ValidationService { private final SessionCache sessionCache; @@ -394,70 +397,82 @@ public class ValidationService { if (sessionId != null) { System.out.println("No such cached session exists for session id " + sessionId + ", re-instantiating validator."); } - System.out.print(" Load FHIR v" + cliContext.getSv() + " from " + definitions); - ValidationEngine validator = new ValidationEngine.ValidationEngineBuilder().withTHO(false).withVersion(cliContext.getSv()).withTimeTracker(tt).withUserAgent("fhir/validator").fromSource(definitions); - + ValidationEngine validator = buildValidationEngine(cliContext, definitions, tt); sessionId = sessionCache.cacheSession(validator); - - FhirPublication ver = FhirPublication.fromCode(cliContext.getSv()); - System.out.println(" - " + validator.getContext().countAllCaches() + " resources (" + tt.milestone() + ")"); - IgLoader igLoader = new IgLoader(validator.getPcm(), validator.getContext(), validator.getVersion(), validator.isDebug()); - igLoader.loadIg(validator.getIgs(), validator.getBinaries(), "hl7.terminology", false); - if (!VersionUtilities.isR5Ver(validator.getContext().getVersion())) { - igLoader.loadIg(validator.getIgs(), validator.getBinaries(), "hl7.fhir.uv.extensions", false); - } - System.out.print(" Terminology server " + cliContext.getTxServer()); - String txver = validator.setTerminologyServer(cliContext.getTxServer(), cliContext.getTxLog(), ver); - System.out.println(" - Version " + txver + " (" + tt.milestone() + ")"); - validator.setDebug(cliContext.isDoDebug()); - validator.getContext().setLogger(new SystemOutLoggingService(cliContext.isDoDebug())); - for (String src : cliContext.getIgs()) { - igLoader.loadIg(validator.getIgs(), validator.getBinaries(), src, cliContext.isRecursive()); - } - System.out.println(" Package Summary: "+validator.getContext().loadedPackageSummary()); - System.out.print(" Get set... "); - validator.setQuestionnaireMode(cliContext.getQuestionnaireMode()); - validator.setLevel(cliContext.getLevel()); - validator.setDoNative(cliContext.isDoNative()); - validator.setHintAboutNonMustSupport(cliContext.isHintAboutNonMustSupport()); - for (String s : cliContext.getExtensions()) { - if ("any".equals(s)) { - validator.setAnyExtensionsAllowed(true); - } else { - validator.getExtensionDomains().add(s); - } - } - validator.setLanguage(cliContext.getLang()); - validator.setLocale(cliContext.getLocale()); - validator.setSnomedExtension(cliContext.getSnomedCTCode()); - validator.setAssumeValidRestReferences(cliContext.isAssumeValidRestReferences()); - validator.setShowMessagesFromReferences(cliContext.isShowMessagesFromReferences()); - validator.setDoImplicitFHIRPathStringConversion(cliContext.isDoImplicitFHIRPathStringConversion()); - validator.setHtmlInMarkdownCheck(cliContext.getHtmlInMarkdownCheck()); - validator.setNoExtensibleBindingMessages(cliContext.isNoExtensibleBindingMessages()); - validator.setNoUnicodeBiDiControlChars(cliContext.isNoUnicodeBiDiControlChars()); - validator.setNoInvariantChecks(cliContext.isNoInvariants()); - validator.setWantInvariantInMessage(cliContext.isWantInvariantsInMessages()); - validator.setSecurityChecks(cliContext.isSecurityChecks()); - validator.setCrumbTrails(cliContext.isCrumbTrails()); - validator.setForPublication(cliContext.isForPublication()); - validator.setShowTimes(cliContext.isShowTimes()); - validator.setAllowExampleUrls(cliContext.isAllowExampleUrls()); - StandAloneValidatorFetcher fetcher = new StandAloneValidatorFetcher(validator.getPcm(), validator.getContext(), validator); - validator.setFetcher(fetcher); - validator.getContext().setLocator(fetcher); - validator.getBundleValidationRules().addAll(cliContext.getBundleValidationRules()); - validator.setJurisdiction(CodeSystemUtilities.readCoding(cliContext.getJurisdiction())); - TerminologyCache.setNoCaching(cliContext.isNoInternalCaching()); - validator.prepare(); // generate any missing snapshots - System.out.println(" go (" + tt.milestone() + ")"); } else { System.out.println("Cached session exists for session id " + sessionId + ", returning stored validator session id."); } return sessionId; } + protected ValidationEngine.ValidationEngineBuilder getValidationEngineBuilder() { + return new ValidationEngine.ValidationEngineBuilder(); + } + @Nonnull + protected ValidationEngine buildValidationEngine( CliContext cliContext, String definitions, TimeTracker timeTracker) throws IOException, URISyntaxException { + System.out.print(" Load FHIR v" + cliContext.getSv() + " from " + definitions); + ValidationEngine validationEngine = getValidationEngineBuilder().withTHO(false).withVersion(cliContext.getSv()).withTimeTracker(timeTracker).withUserAgent("fhir/validator").fromSource(definitions); + + System.out.println(" - " + validationEngine.getContext().countAllCaches() + " resources (" + timeTracker.milestone() + ")"); + + loadIgsAndExtensions(validationEngine, cliContext, timeTracker); + System.out.print(" Get set... "); + validationEngine.setQuestionnaireMode(cliContext.getQuestionnaireMode()); + validationEngine.setLevel(cliContext.getLevel()); + validationEngine.setDoNative(cliContext.isDoNative()); + validationEngine.setHintAboutNonMustSupport(cliContext.isHintAboutNonMustSupport()); + for (String s : cliContext.getExtensions()) { + if ("any".equals(s)) { + validationEngine.setAnyExtensionsAllowed(true); + } else { + validationEngine.getExtensionDomains().add(s); + } + } + validationEngine.setLanguage(cliContext.getLang()); + validationEngine.setLocale(cliContext.getLocale()); + validationEngine.setSnomedExtension(cliContext.getSnomedCTCode()); + validationEngine.setAssumeValidRestReferences(cliContext.isAssumeValidRestReferences()); + validationEngine.setShowMessagesFromReferences(cliContext.isShowMessagesFromReferences()); + validationEngine.setDoImplicitFHIRPathStringConversion(cliContext.isDoImplicitFHIRPathStringConversion()); + validationEngine.setHtmlInMarkdownCheck(cliContext.getHtmlInMarkdownCheck()); + validationEngine.setNoExtensibleBindingMessages(cliContext.isNoExtensibleBindingMessages()); + validationEngine.setNoUnicodeBiDiControlChars(cliContext.isNoUnicodeBiDiControlChars()); + validationEngine.setNoInvariantChecks(cliContext.isNoInvariants()); + validationEngine.setWantInvariantInMessage(cliContext.isWantInvariantsInMessages()); + validationEngine.setSecurityChecks(cliContext.isSecurityChecks()); + validationEngine.setCrumbTrails(cliContext.isCrumbTrails()); + validationEngine.setForPublication(cliContext.isForPublication()); + validationEngine.setShowTimes(cliContext.isShowTimes()); + validationEngine.setAllowExampleUrls(cliContext.isAllowExampleUrls()); + StandAloneValidatorFetcher fetcher = new StandAloneValidatorFetcher(validationEngine.getPcm(), validationEngine.getContext(), validationEngine); + validationEngine.setFetcher(fetcher); + validationEngine.getContext().setLocator(fetcher); + validationEngine.getBundleValidationRules().addAll(cliContext.getBundleValidationRules()); + validationEngine.setJurisdiction(CodeSystemUtilities.readCoding(cliContext.getJurisdiction())); + TerminologyCache.setNoCaching(cliContext.isNoInternalCaching()); + validationEngine.prepare(); // generate any missing snapshots + System.out.println(" go (" + timeTracker.milestone() + ")"); + return validationEngine; + } + + protected void loadIgsAndExtensions(ValidationEngine validationEngine, CliContext cliContext, TimeTracker timeTracker) throws IOException, URISyntaxException { + FhirPublication ver = FhirPublication.fromCode(cliContext.getSv()); + IgLoader igLoader = new IgLoader(validationEngine.getPcm(), validationEngine.getContext(), validationEngine.getVersion(), validationEngine.isDebug()); + igLoader.loadIg(validationEngine.getIgs(), validationEngine.getBinaries(), "hl7.terminology", false); + if (!VersionUtilities.isR5Ver(validationEngine.getContext().getVersion())) { + igLoader.loadIg(validationEngine.getIgs(), validationEngine.getBinaries(), "hl7.fhir.uv.extensions", false); + } + System.out.print(" Terminology server " + cliContext.getTxServer()); + String txver = validationEngine.setTerminologyServer(cliContext.getTxServer(), cliContext.getTxLog(), ver); + System.out.println(" - Version " + txver + " (" + timeTracker.milestone() + ")"); + validationEngine.setDebug(cliContext.isDoDebug()); + validationEngine.getContext().setLogger(new SystemOutLoggingService(cliContext.isDoDebug())); + for (String src : cliContext.getIgs()) { + igLoader.loadIg(validationEngine.getIgs(), validationEngine.getBinaries(), src, cliContext.isRecursive()); + } + System.out.println(" Package Summary: "+ validationEngine.getContext().loadedPackageSummary()); + } public String determineVersion(CliContext cliContext) throws Exception { diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/Params.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/Params.java index 23c5700f9..7aab8bd95 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/Params.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/Params.java @@ -92,6 +92,7 @@ public class Params { public static final String TARGET = "-target"; public static final String SOURCE = "-source"; public static final String FILTER = "-filter"; + private static final String FHIR_SETTINGS_PARAM = "-fhir-settings"; /** * Checks the list of passed in params to see if it contains the passed in param. @@ -128,6 +129,12 @@ public class Params { for (int i = 0; i < args.length; i++) { if (args[i].equals(VERSION)) { cliContext.setSv(VersionUtilities.getCurrentPackageVersion(args[++i])); + } else if (args[i].equals(FHIR_SETTINGS_PARAM)) { + final String fhirSettingsFilePath = args[++i]; + if (! new File(fhirSettingsFilePath).exists()) { + throw new Error("Cannot find fhir-settings file: " + fhirSettingsFilePath); + } + cliContext.setFhirSettingsFile(fhirSettingsFilePath); } else if (args[i].equals(OUTPUT)) { if (i + 1 == args.length) throw new Error("Specified -output without indicating output file"); diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/cli/services/ValidationServiceTest.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/cli/services/ValidationServiceTest.java index 279e37fbe..4df7d8b1d 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/cli/services/ValidationServiceTest.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/cli/services/ValidationServiceTest.java @@ -1,10 +1,12 @@ package org.hl7.fhir.validation.cli.services; import org.apache.commons.io.IOUtils; +import org.hl7.fhir.r5.context.SimpleWorkerContext; import org.hl7.fhir.r5.elementmodel.Manager; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.test.utils.TestingUtilities; -import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.TimeTracker; +import org.hl7.fhir.utilities.tests.ResourceLoaderTests; import org.hl7.fhir.validation.ValidationEngine; import org.hl7.fhir.validation.cli.model.CliContext; import org.hl7.fhir.validation.cli.model.FileInfo; @@ -15,8 +17,12 @@ import org.junit.jupiter.api.Test; import org.mockito.ArgumentMatchers; import org.mockito.Mockito; +import java.io.IOException; import java.io.InputStream; +import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -29,7 +35,7 @@ import static org.mockito.AdditionalMatchers.and; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; -class ValidationServiceTest { +class ValidationServiceTest { final String DUMMY_SOURCE = "dummySource"; final String DUMMY_SOURCE1 = "dummySource1"; @@ -215,4 +221,50 @@ class ValidationServiceTest { cliContext = new CliContext().setSources(Arrays.asList(DUMMY_SOURCE1, DUMMY_SOURCE2, DUMMY_SOURCE3)); return cliContext; } + + /* This is a particularly long way to test that a single field in ValidationEngine was set. + However, it does provide example code to test other parts of the buildValidationEngine method as well. + */ + @Test + public void buildValidationEngineTest() throws IOException, URISyntaxException { + + final org.hl7.fhir.utilities.TimeTracker timeTracker = mock(org.hl7.fhir.utilities.TimeTracker.class); + + final SimpleWorkerContext workerContext = mock(SimpleWorkerContext.class); + + final ValidationEngine validationEngine = mock(ValidationEngine.class); + when(validationEngine.getContext()).thenReturn(workerContext); + + final ValidationService validationService = new ValidationService() { + @Override + protected ValidationEngine.ValidationEngineBuilder getValidationEngineBuilder() { + + ValidationEngine.ValidationEngineBuilder validationEngineBuilder = mock(ValidationEngine.ValidationEngineBuilder.class); + + when(validationEngineBuilder.withTHO(anyBoolean())).thenReturn(validationEngineBuilder); + when(validationEngineBuilder.withVersion(isNull())).thenReturn(validationEngineBuilder); + when(validationEngineBuilder.withTimeTracker(any())).thenReturn(validationEngineBuilder); + when(validationEngineBuilder.withUserAgent(anyString())).thenReturn(validationEngineBuilder); + try { + when(validationEngineBuilder.fromSource(isNull())).thenReturn(validationEngine); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + return validationEngineBuilder; + } + + @Override + protected void loadIgsAndExtensions(ValidationEngine validationEngine, CliContext cliContext, TimeTracker timeTracker) throws IOException, URISyntaxException { + //Don't care. Do nothing. + } + }; + + + + CliContext cliContext = new CliContext(); + + validationService.buildValidationEngine(cliContext, null, timeTracker); + } } \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/cli/utils/ParamsTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/cli/utils/ParamsTests.java index c60c8537a..391b06586 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/cli/utils/ParamsTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/cli/utils/ParamsTests.java @@ -1,8 +1,15 @@ package org.hl7.fhir.validation.cli.utils; import org.hl7.fhir.validation.cli.model.CliContext; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; + +import java.io.File; +import java.nio.file.Files; import java.util.Locale; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertEquals; public class ParamsTests { @@ -11,4 +18,20 @@ public class ParamsTests { CliContext cliContext = Params.loadCliContext(new String[]{"-locale", "de"}); assertEquals(Locale.GERMAN, cliContext.getLocale()); } + + @Test + void testFhirSettingsFile() throws Exception { + File tempFile = Files.createTempFile("fhir-settings", "json").toFile(); + CliContext cliContext = Params.loadCliContext(new String[]{"-fhir-settings", tempFile.getAbsolutePath()}); + assertEquals(tempFile.getAbsolutePath(), cliContext.getFhirSettingsFile()); + } + + @Test + void testFhirSettingsFileDoesntExist() { + + java.lang.Error error = Assertions.assertThrows(java.lang.Error.class, () -> { + CliContext cliContext = Params.loadCliContext(new String[]{"-fhir-settings", "this-does-not-exist.json"}); + }); + assertThat(error.getMessage(), containsString("this-does-not-exist.json")); + } } \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/1.0.2/loinc.cache b/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/1.0.2/loinc.cache index 350001ac4..638a95b1e 100644 --- a/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/1.0.2/loinc.cache +++ b/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/1.0.2/loinc.cache @@ -10,3 +10,14 @@ v: { "system" : "http://loinc.org" } ------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://loinc.org", + "code" : "3141-9", + "display" : "Weight Measured" +}, "valueSet" :null, "langs":"[en]", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "versionFlexible":"false"}#### +v: { + "display" : "Body weight Measured", + "code" : "3141-9", + "system" : "http://loinc.org" +} +------------------------------------------------------------------------------------- diff --git a/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/1.0.2/snomed.cache b/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/1.0.2/snomed.cache index cf5333899..b32dead31 100644 --- a/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/1.0.2/snomed.cache +++ b/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/1.0.2/snomed.cache @@ -10,3 +10,14 @@ v: { "system" : "http://snomed.info/sct" } ------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://snomed.info/sct", + "code" : "27113001", + "display" : "Body weight" +}, "valueSet" :null, "langs":"[en]", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "versionFlexible":"false"}#### +v: { + "display" : "Body weight", + "code" : "27113001", + "system" : "http://snomed.info/sct" +} +------------------------------------------------------------------------------------- diff --git a/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/1.0.2/ucum.cache b/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/1.0.2/ucum.cache index 5199f2c21..2864a6031 100644 --- a/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/1.0.2/ucum.cache +++ b/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/1.0.2/ucum.cache @@ -9,3 +9,13 @@ v: { "system" : "http://unitsofmeasure.org" } ------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://unitsofmeasure.org", + "code" : "[lb_av]" +}, "valueSet" :null, "langs":"[en]", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "versionFlexible":"false"}#### +v: { + "display" : "[lb_av]", + "code" : "[lb_av]", + "system" : "http://unitsofmeasure.org" +} +-------------------------------------------------------------------------------------