diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 7ab9bcb1d..d4626a173 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,23 +1,7 @@ ## Validator Changes -* Fix issue where valdiator not retaining extension context when checking constraint expressions in profiles -* Validate min-length when found in extension -* Correct bug parsing json-property-key values with meant validation failed -* Fix problem validating json-property-key value pairs -* Fix special case r5 loading of terminology to fix validation error on ExampleScenario -* Improve handling of JSON format errors -* Fix slicing by type and profile to allow multiple options per slice -* List measure choices when a match by version can't be found -* Validate fhirpath expression in slice discriminators +* no changes ## Other code changes -* More work on code generation for profiles -* Render min-length extension on profiles -* Clone SQL on FHIR engine to R4, and update FHIRPath engine based on R5 current code -* Update SQL on FHIR engine to allow push as well as pull -* Change R5 tx server to use http://tx.fhir.org/r5 (instead of /r4) -* Update output from tx-tester to include release ready statement -* Fix rendering of Logical Models for polymorphic elements, and rendering target profiles with versions -* Render contained resources in List resource -* #1790 - Fix versionFromCanonical returns system instead and systemFromCanonical returns version +* Test Release diff --git a/i18n-coverage-table.png b/i18n-coverage-table.png index f578b0ec8..79464b971 100644 Binary files a/i18n-coverage-table.png and b/i18n-coverage-table.png differ diff --git a/i18n-coverage.csv b/i18n-coverage.csv index 58fd326c1..b7e145970 100644 --- a/i18n-coverage.csv +++ b/i18n-coverage.csv @@ -1,5 +1,5 @@ Locale,Coverage #,Coverage % -de,831,40% -es,714,34% -ja,902,43% -nl,1988,96% +de,829,40% +es,712,34% +ja,900,43% +nl,1986,96% diff --git a/master-branch-pipeline.yml b/master-branch-pipeline.yml index bdafd4688..3c7c82fad 100644 --- a/master-branch-pipeline.yml +++ b/master-branch-pipeline.yml @@ -117,6 +117,7 @@ jobs: # This is done for the master branch merges only. - task: Maven@4 displayName: 'Deploy to GitHub packages' + enabled: false inputs: mavenPomFile: '$(System.DefaultWorkingDirectory)/pom.xml' goals: jar:jar deploy:deploy @@ -196,4 +197,4 @@ jobs: git push https://$(GIT_PAT)@github.com/hapifhir/org.hl7.fhir.core.git - displayName: 'Push updated csv and plot to git.' \ No newline at end of file + displayName: 'Push updated csv and plot to git.' diff --git a/org.hl7.fhir.convertors/pom.xml b/org.hl7.fhir.convertors/pom.xml index da261b5b1..c0ec3f890 100644 --- a/org.hl7.fhir.convertors/pom.xml +++ b/org.hl7.fhir.convertors/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 6.4.1-SNAPSHOT + 6.4.2-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/analytics/PackageVisitor.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/analytics/PackageVisitor.java index 442bdc68c..232db1642 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/analytics/PackageVisitor.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/analytics/PackageVisitor.java @@ -3,12 +3,7 @@ package org.hl7.fhir.convertors.analytics; import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import javax.xml.parsers.ParserConfigurationException; @@ -241,7 +236,7 @@ public class PackageVisitor { File co = ManagedFileAccess.file(Utilities.path(cache, pid+"."+manifest.asString("date")+".tgz")); if (!co.exists()) { - HTTPResult res = ManagedWebAccess.get(repo+"/package.tgz?nocache=" + System.currentTimeMillis()); + HTTPResult res = ManagedWebAccess.get(Arrays.asList("web"), repo+"/package.tgz?nocache=" + System.currentTimeMillis()); res.checkThrowException(); TextFile.bytesToFile(res.getContent(), co); } @@ -338,7 +333,7 @@ public class PackageVisitor { System.out.println("Feed "+str); try { - HTTPResult res = ManagedWebAccess.get(str+"?nocache=" + System.currentTimeMillis()); + HTTPResult res = ManagedWebAccess.get(Arrays.asList("web"), str+"?nocache=" + System.currentTimeMillis()); res.checkThrowException(); Document xml = XMLUtil.parseToDom(res.getContent()); for (Element channel : XMLUtil.getNamedChildren(xml.getDocumentElement(), "channel")) { diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/CKMImporter.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/CKMImporter.java index e4d04ada7..7aeddc01d 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/CKMImporter.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/CKMImporter.java @@ -4,6 +4,7 @@ import java.io.ByteArrayInputStream; import java.io.File; import java.io.InputStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import javax.xml.parsers.DocumentBuilder; @@ -126,7 +127,7 @@ public class CKMImporter { private Document loadXml(String address) throws Exception { - HTTPResult res = ManagedWebAccess.get(address, "application/xml"); + HTTPResult res = ManagedWebAccess.get(Arrays.asList("web"), address, "application/xml"); res.checkThrowException(); InputStream xml = new ByteArrayInputStream(res.getContent()); diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/ICD11Generator.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/ICD11Generator.java index 0e7a391d2..78713b099 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/ICD11Generator.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/ICD11Generator.java @@ -1,6 +1,7 @@ package org.hl7.fhir.convertors.misc; import java.io.IOException; +import java.util.Arrays; import java.util.Date; import java.util.HashSet; import java.util.Set; @@ -394,7 +395,7 @@ public class ICD11Generator { private JsonObject fetchJson(String source) throws IOException { - HTTPResult res = ManagedWebAccess.accessor().withHeader("API-Version", "v2").withHeader("Accept-Language", "en").get(source,"application/json"); + HTTPResult res = ManagedWebAccess.accessor(Arrays.asList("web")).withHeader("API-Version", "v2").withHeader("Accept-Language", "en").get(source,"application/json"); res.checkThrowException(); return JsonParser.parseObject(res.getContent()); } diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/txClient/TerminologyClientR2.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/txClient/TerminologyClientR2.java index f005cdb35..5cbc96328 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/txClient/TerminologyClientR2.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/txClient/TerminologyClientR2.java @@ -163,6 +163,11 @@ public class TerminologyClientR2 implements ITerminologyClient { return (CapabilityStatement) VersionConvertorFactory_10_50.convertResource(client.getConformanceStatementQuick()); } + @Override + public CapabilityStatement getCapabilitiesStatement() throws FHIRException { + return (CapabilityStatement) VersionConvertorFactory_10_50.convertResource(client.getConformanceStatement()); + } + @Override public Parameters lookupCode(Map params) throws FHIRException { return (Parameters) VersionConvertorFactory_10_50.convertResource(client.lookupCode(params)); diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/txClient/TerminologyClientR3.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/txClient/TerminologyClientR3.java index 792cb04ef..84f51cd38 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/txClient/TerminologyClientR3.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/txClient/TerminologyClientR3.java @@ -153,6 +153,11 @@ public class TerminologyClientR3 implements ITerminologyClient { return (CapabilityStatement) VersionConvertorFactory_30_50.convertResource(client.getCapabilitiesStatementQuick()); } + @Override + public CapabilityStatement getCapabilitiesStatement() throws FHIRException { + return (CapabilityStatement) VersionConvertorFactory_30_50.convertResource(client.getCapabilitiesStatement()); + } + @Override public Parameters lookupCode(Map params) throws FHIRException { return (Parameters) VersionConvertorFactory_30_50.convertResource(client.lookupCode(params)); diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/txClient/TerminologyClientR4.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/txClient/TerminologyClientR4.java index 7e40c994b..313de8c67 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/txClient/TerminologyClientR4.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/txClient/TerminologyClientR4.java @@ -64,7 +64,7 @@ public class TerminologyClientR4 implements ITerminologyClient { } public FhirPublication getActualVersion() { - return FhirPublication.STU3; + return FhirPublication.R4; } @@ -177,6 +177,11 @@ public class TerminologyClientR4 implements ITerminologyClient { return (CapabilityStatement) VersionConvertorFactory_40_50.convertResource(client.getCapabilitiesStatementQuick()); } + @Override + public CapabilityStatement getCapabilitiesStatement() throws FHIRException { + return (CapabilityStatement) VersionConvertorFactory_40_50.convertResource(client.getCapabilitiesStatement()); + } + @Override public Parameters lookupCode(Map params) throws FHIRException { return (Parameters) VersionConvertorFactory_40_50.convertResource(client.lookupCode(params)); diff --git a/org.hl7.fhir.dstu2/pom.xml b/org.hl7.fhir.dstu2/pom.xml index 881479b40..7d13c552e 100644 --- a/org.hl7.fhir.dstu2/pom.xml +++ b/org.hl7.fhir.dstu2/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 6.4.1-SNAPSHOT + 6.4.2-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.dstu2016may/pom.xml b/org.hl7.fhir.dstu2016may/pom.xml index 01249e0e4..b6f329a0c 100644 --- a/org.hl7.fhir.dstu2016may/pom.xml +++ b/org.hl7.fhir.dstu2016may/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 6.4.1-SNAPSHOT + 6.4.2-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.dstu3/pom.xml b/org.hl7.fhir.dstu3/pom.xml index aef8d1dcc..c23be2334 100644 --- a/org.hl7.fhir.dstu3/pom.xml +++ b/org.hl7.fhir.dstu3/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 6.4.1-SNAPSHOT + 6.4.2-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.r4/pom.xml b/org.hl7.fhir.r4/pom.xml index 179e00ac6..95f120476 100644 --- a/org.hl7.fhir.r4/pom.xml +++ b/org.hl7.fhir.r4/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 6.4.1-SNAPSHOT + 6.4.2-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/conformance/ProfileComparer.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/conformance/ProfileComparer.java index f9d34478d..0f770bce4 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/conformance/ProfileComparer.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/conformance/ProfileComparer.java @@ -31,12 +31,7 @@ package org.hl7.fhir.r4.conformance; import java.io.File; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.FHIRFormatError; @@ -1384,7 +1379,7 @@ public class ProfileComparer { if (f.exists()) return TextFile.fileToString(f); - HTTPResult res = ManagedWebAccess.get(source); + HTTPResult res = ManagedWebAccess.get(Arrays.asList("web"), source); res.checkThrowException(); String result = TextFile.bytesToString(res.getContent()); TextFile.stringToFile(result, f); diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/client/FHIRToolingClient.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/client/FHIRToolingClient.java index 11451ad42..5495dca05 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/client/FHIRToolingClient.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/client/FHIRToolingClient.java @@ -71,7 +71,6 @@ public class FHIRToolingClient extends FHIRBaseToolingClient { @Setter private ResourceFormat preferredResourceFormat; private int maxResultSetSize = -1;// _count - private CapabilityStatement capabilities; @Getter @Setter private Client client = new Client(); @@ -100,13 +99,6 @@ public class FHIRToolingClient extends FHIRBaseToolingClient { this.maxResultSetSize = -1; } - private void checkCapabilities() { - try { - capabilities = getCapabilitiesStatementQuick(); - } catch (Throwable e) { - } - } - public String getPreferredResourceFormat() { return preferredResourceFormat.getHeader(); } @@ -130,10 +122,10 @@ public class FHIRToolingClient extends FHIRBaseToolingClient { return capabilities; } - public CapabilityStatement getCapabilitiesStatement() { + public CapabilityStatement getCapabilitiesStatementQuick() { CapabilityStatement conformance = null; try { - conformance = (CapabilityStatement) client.issueGetResourceRequest(resourceAddress.resolveMetadataUri(false), + conformance = (CapabilityStatement) client.issueGetResourceRequest(resourceAddress.resolveMetadataUri(true), withVer(getPreferredResourceFormat(), "4.0"), generateHeaders(false), "CapabilitiesStatement", timeoutNormal).getReference(); } catch (Exception e) { throw new FHIRException("Error fetching the server's conformance statement", e); @@ -141,18 +133,15 @@ public class FHIRToolingClient extends FHIRBaseToolingClient { return conformance; } - public CapabilityStatement getCapabilitiesStatementQuick() throws EFhirClientException { - if (capabilities != null) - return capabilities; - try { - capabilities = (CapabilityStatement) client.issueGetResourceRequest(resourceAddress.resolveMetadataUri(true), - withVer(getPreferredResourceFormat(), "4.0"), generateHeaders(false), "CapabilitiesStatement-Quick", timeoutNormal) - .getReference(); - } catch (Exception e) { - throw new FHIRException("Error fetching the server's capability statement: " + e.getMessage(), e); - } - return capabilities; - } + public CapabilityStatement getCapabilitiesStatement() throws EFhirClientException { + try { + return (CapabilityStatement) client.issueGetResourceRequest(resourceAddress.resolveMetadataUri(false), + withVer(getPreferredResourceFormat(), "4.0"), generateHeaders(false), "CapabilitiesStatement-Quick", timeoutNormal) + .getReference(); + } catch (Exception e) { + throw new FHIRException("Error fetching the server's capability statement: " + e.getMessage(), e); + } + } public Resource read(String resourceClass, String id) {// TODO Change this to AddressableResource recordUse(); @@ -562,8 +551,7 @@ public class FHIRToolingClient extends FHIRBaseToolingClient { } public String getServerVersion() { - checkCapabilities(); - return capabilities == null ? null : capabilities.getSoftware().getVersion(); + return getCapabilitiesStatementQuick().getSoftware().getVersion(); } public Bundle search(String type, String criteria) { diff --git a/org.hl7.fhir.r4b/pom.xml b/org.hl7.fhir.r4b/pom.xml index a25a275d8..5e9ce3dd3 100644 --- a/org.hl7.fhir.r4b/pom.xml +++ b/org.hl7.fhir.r4b/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 6.4.1-SNAPSHOT + 6.4.2-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/context/TextClientLogger.java b/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/context/TextClientLogger.java index fa29392ae..c7a680e63 100644 --- a/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/context/TextClientLogger.java +++ b/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/context/TextClientLogger.java @@ -61,11 +61,11 @@ public class TextClientLogger extends BaseLogger implements ToolingClientLogger file.println("\r\n--- " + id + " -----------------\r\nRequest: \r\n"); file.println(method + " " + url + " HTTP/1.0"); for (String s : headers) - file.println(Utilities.escapeXml(s)); + file.println(s); if (body != null) { file.println(""); try { - file.println(Utilities.escapeXml(new String(body, "UTF-8"))); + file.println(new String(body, "UTF-8")); } catch (UnsupportedEncodingException e) { } } @@ -82,7 +82,7 @@ public class TextClientLogger extends BaseLogger implements ToolingClientLogger if (body != null) { file.println(""); try { - file.println(Utilities.escapeXml(new String(body, "UTF-8"))); + file.println(new String(body, "UTF-8")); } catch (UnsupportedEncodingException e) { } } diff --git a/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/terminologies/TerminologyCacheManager.java b/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/terminologies/TerminologyCacheManager.java index 819d36fc2..2a211f7ba 100644 --- a/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/terminologies/TerminologyCacheManager.java +++ b/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/terminologies/TerminologyCacheManager.java @@ -9,6 +9,7 @@ import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Arrays; import java.util.Date; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -79,7 +80,7 @@ public class TerminologyCacheManager { try { System.out.println("Initialise terminology cache from " + source); - HTTPResult res = ManagedWebAccess.get(source + "?nocache=" + System.currentTimeMillis()); + HTTPResult res = ManagedWebAccess.get(Arrays.asList("web"), source + "?nocache=" + System.currentTimeMillis()); res.checkThrowException(); unzip(new ByteArrayInputStream(res.getContent()), cacheFolder); } catch (Exception e) { @@ -148,7 +149,7 @@ public class TerminologyCacheManager { String url = "https://tx.fhir.org/post/tx-cache/" + ghOrg + "/" + ghRepo + "/" + ghBranch + ".zip"; System.out.println("Sending tx-cache to " + url + " (" + Utilities.describeSize(bs.toByteArray().length) + ")"); - HTTPResult res = ManagedWebAccess.accessor() + HTTPResult res = ManagedWebAccess.accessor(Arrays.asList("web")) .withBasicAuth(token.substring(0, token.indexOf(':')), token.substring(token.indexOf(':') + 1)) .put(url, bs.toByteArray(), null, "application/zip"); if (res.getCode() >= 300) { diff --git a/org.hl7.fhir.r5/pom.xml b/org.hl7.fhir.r5/pom.xml index e17a32aa9..9e1e21c67 100644 --- a/org.hl7.fhir.r5/pom.xml +++ b/org.hl7.fhir.r5/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 6.4.1-SNAPSHOT + 6.4.2-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java index 46bbab983..4aa657d35 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java @@ -119,6 +119,7 @@ import org.hl7.fhir.utilities.xml.SchematronWriter.Rule; import org.hl7.fhir.utilities.xml.SchematronWriter.SchematronType; import org.hl7.fhir.utilities.xml.SchematronWriter.Section; + /** * This class provides a set of utility operations for working with Profiles. * Key functionality: @@ -490,8 +491,8 @@ public class ProfileUtilities { return this; } - public SourcedChildDefinitions getChildMap(StructureDefinition profile, ElementDefinition element) throws DefinitionException { - String cacheKey = "cm."+profile.getVersionedUrl()+"#"+(element.hasId() ? element.getId() : element.getPath()); + public SourcedChildDefinitions getChildMap(StructureDefinition profile, ElementDefinition element, boolean chaseTypes) throws DefinitionException { + String cacheKey = "cm."+profile.getVersionedUrl()+"#"+(element.hasId() ? element.getId() : element.getPath())+"."+chaseTypes; if (childMapCache.containsKey(cacheKey)) { return childMapCache.get(cacheKey); } @@ -519,7 +520,7 @@ public class ProfileUtilities { for (ElementDefinition e : list) { if (id.equals(e.getId())) - return getChildMap(src, e); + return getChildMap(src, e, true); } throw new DefinitionException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_NAME_REFERENCE__AT_PATH_, element.getContentReference(), element.getPath())); @@ -536,6 +537,30 @@ public class ProfileUtilities { } else break; } + if (res.isEmpty() && chaseTypes) { + // we've got no in-line children. Some consumers of this routine will figure this out for themselves but most just want to walk into + // the type children. + src = null; + if (element.getType().isEmpty()) { + throw new DefinitionException("No defined children and no type information on element '"+element.getId()+"'"); + } else if (element.getType().size() > 1) { + throw new DefinitionException("No defined children and multiple possible types '"+element.typeSummary()+"' on element '"+element.getId()+"'"); + } else if (element.getType().get(0).getProfile().size() > 1) { + throw new DefinitionException("No defined children and multiple possible type profiles '"+element.typeSummary()+"' on element '"+element.getId()+"'"); + } else if (element.getType().get(0).hasProfile()) { + src = context.fetchResource(StructureDefinition.class, element.getType().get(0).getProfile().get(0).getValue()); + if (src == null) { + throw new DefinitionException("No defined children and unknown type profile '"+element.typeSummary()+"' on element '"+element.getId()+"'"); + } + } else { + src = context.fetchTypeDefinition(element.getType().get(0).getWorkingCode()); + if (src == null) { + throw new DefinitionException("No defined children and unknown type '"+element.typeSummary()+"' on element '"+element.getId()+"'"); + } + } + SourcedChildDefinitions scd = getChildMap(src, src.getSnapshot().getElementFirstRep(), false); + res = scd.list; + } SourcedChildDefinitions result = new SourcedChildDefinitions(src, res); childMapCache.put(cacheKey, result); return result; @@ -4085,7 +4110,7 @@ public class ProfileUtilities { private org.hl7.fhir.r5.elementmodel.Element generateExample(StructureDefinition profile, ExampleValueAccessor accessor) throws FHIRException { ElementDefinition ed = profile.getSnapshot().getElementFirstRep(); org.hl7.fhir.r5.elementmodel.Element r = new org.hl7.fhir.r5.elementmodel.Element(ed.getPath(), new Property(context, ed, profile)); - SourcedChildDefinitions children = getChildMap(profile, ed); + SourcedChildDefinitions children = getChildMap(profile, ed, true); for (ElementDefinition child : children.getList()) { if (child.getPath().endsWith(".id")) { org.hl7.fhir.r5.elementmodel.Element id = new org.hl7.fhir.r5.elementmodel.Element("id", new Property(context, child, profile)); @@ -4107,7 +4132,7 @@ public class ProfileUtilities { } else { org.hl7.fhir.r5.elementmodel.Element res = new org.hl7.fhir.r5.elementmodel.Element(tail(ed.getPath()), new Property(context, ed, profile)); boolean hasValue = false; - SourcedChildDefinitions children = getChildMap(profile, ed); + SourcedChildDefinitions children = getChildMap(profile, ed, true); for (ElementDefinition child : children.getList()) { if (!child.hasContentReference()) { org.hl7.fhir.r5.elementmodel.Element e = createExampleElement(profile, child, accessor); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/ObjectConverter.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/ObjectConverter.java index 6c9c26591..6d366baaa 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/ObjectConverter.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/ObjectConverter.java @@ -93,7 +93,7 @@ public class ObjectConverter { if (sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE) res.setValue(((PrimitiveType) base).asStringValue()); - SourcedChildDefinitions children = profileUtilities.getChildMap(sd, sd.getSnapshot().getElementFirstRep()); + SourcedChildDefinitions children = profileUtilities.getChildMap(sd, sd.getSnapshot().getElementFirstRep(), true); for (ElementDefinition child : children.getList()) { String n = tail(child.getPath()); if (sd.getKind() != StructureDefinitionKind.PRIMITIVETYPE || !"value".equals(n)) { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Property.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Property.java index ec7cf72d0..7f5e814a3 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Property.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Property.java @@ -385,7 +385,7 @@ public class Property { ElementDefinition ed = definition; StructureDefinition sd = structure; boolean isCDA = isCDAElement(structure); - SourcedChildDefinitions children = profileUtilities.getChildMap(sd, ed); + SourcedChildDefinitions children = profileUtilities.getChildMap(sd, ed, false); String url = null; if (children.getList().isEmpty() || isElementWithOnlyExtension(ed, children.getList())) { // ok, find the right definitions @@ -459,7 +459,7 @@ public class Property { sd = context.fetchResource(StructureDefinition.class, url); if (sd == null) throw new DefinitionException("Unable to find definition '"+url+"' for type '"+t+"' for name '"+elementName+"' on property "+definition.getPath()); - children = profileUtilities.getChildMap(sd, sd.getSnapshot().getElement().get(0)); + children = profileUtilities.getChildMap(sd, sd.getSnapshot().getElement().get(0), false); } } List properties = new ArrayList(); @@ -493,7 +493,7 @@ public class Property { protected List getChildProperties(TypeDetails type) throws DefinitionException { ElementDefinition ed = definition; StructureDefinition sd = structure; - SourcedChildDefinitions children = profileUtilities.getChildMap(sd, ed); + SourcedChildDefinitions children = profileUtilities.getChildMap(sd, ed, false); if (children.getList().isEmpty()) { // ok, find the right definitions String t = null; @@ -519,7 +519,7 @@ public class Property { sd = context.fetchResource(StructureDefinition.class, t); if (sd == null) throw new DefinitionException("Unable to find class '"+t+"' for name '"+ed.getPath()+"' on property "+definition.getPath()); - children = profileUtilities.getChildMap(sd, sd.getSnapshot().getElement().get(0)); + children = profileUtilities.getChildMap(sd, sd.getSnapshot().getElement().get(0), false); } } List properties = new ArrayList(); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHCParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHCParser.java index 1376bdcb6..04d936f98 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHCParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHCParser.java @@ -29,6 +29,9 @@ import org.hl7.fhir.r5.formats.IParser.OutputStyle; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; +import org.hl7.fhir.utilities.http.HTTPRequest; +import org.hl7.fhir.utilities.http.HTTPResult; +import org.hl7.fhir.utilities.http.ManagedWebAccess; import org.hl7.fhir.utilities.json.JsonException; import org.hl7.fhir.utilities.json.model.JsonArray; import org.hl7.fhir.utilities.json.model.JsonElement; @@ -428,6 +431,20 @@ public class SHCParser extends ParserBase { private String getVCIIssuer(List errors, String issuer) { try { JsonObject vci = org.hl7.fhir.utilities.json.parser.JsonParser.parseObjectFromUrl("https://raw.githubusercontent.com/the-commons-project/vci-directory/main/vci-issuers.json"); + + /* HTTPResult httpResult = ManagedWebAccess.httpCall( + new HTTPRequest().withMethod(HTTPVerb.GET).withUrl(new URL("https://raw.githubusercontent.com/the-commons-project/vci-directory/main/vci-issuers.json")) + new URL("https://raw.githubusercontent.com/the-commons-project/vci-directory/main/vci-issuers.json") + HTTPRequest.HttpMethod.GET, + null, + null, + null + + ) + ) + */ + + //JsonObject vci = org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(); for (JsonObject j : vci.getJsonObjects("participating_issuers")) { if (issuer.equals(j.asString("iss"))) { return j.asString("name"); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHLParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHLParser.java index bbbf0e851..971e06090 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHLParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHLParser.java @@ -287,7 +287,7 @@ public class SHLParser extends ParserBase { private HTTPResult fetchFile(String url, String ct) throws IOException { - HTTPResult res = ManagedWebAccess.get(url, ct); + HTTPResult res = ManagedWebAccess.get(Arrays.asList("web"), url, ct); res.checkThrowException(); return res; } @@ -299,7 +299,7 @@ public class SHLParser extends ParserBase { JsonObject j = new JsonObject(); j.add("recipient", "FHIR Validator"); - HTTPResult res = ManagedWebAccess.post(url, org.hl7.fhir.utilities.json.parser.JsonParser.composeBytes(j), "application/json", "application/json"); + HTTPResult res = ManagedWebAccess.post(Arrays.asList("web"), url, org.hl7.fhir.utilities.json.parser.JsonParser.composeBytes(j), "application/json", "application/json"); res.checkThrowException(); return res; } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/fhirpath/FHIRPathEngine.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/fhirpath/FHIRPathEngine.java index 3db26b7e7..c89561a64 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/fhirpath/FHIRPathEngine.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/fhirpath/FHIRPathEngine.java @@ -6619,7 +6619,7 @@ public class FHIRPathEngine { focus = element; } else { SourcedChildDefinitions childDefinitions; - childDefinitions = profileUtilities.getChildMap(sd, element.getElement()); + childDefinitions = profileUtilities.getChildMap(sd, element.getElement(), false); // if that's empty, get the children of the type if (childDefinitions.getList().isEmpty()) { @@ -6627,7 +6627,7 @@ public class FHIRPathEngine { if (sd == null) { throw makeException(expr, I18nConstants.FHIRPATH_RESOLVE_DISCRIMINATOR_CANT_FIND, element.getElement().getType().get(0).getProfile(), element.getElement().getId()); } - childDefinitions = profileUtilities.getChildMap(sd, sd.getSnapshot().getElementFirstRep()); + childDefinitions = profileUtilities.getChildMap(sd, sd.getSnapshot().getElementFirstRep(), false); } for (ElementDefinition t : childDefinitions.getList()) { if (tailMatches(t, expr.getName()) && !t.hasSlicing()) { // GG: slicing is a problem here. This is for an exetnsion with a fixed value (type slicing) @@ -6657,7 +6657,7 @@ public class FHIRPathEngine { focus = new TypedElementDefinition(sd.getSnapshot().getElementFirstRep()); } else if ("extension".equals(expr.getName())) { String targetUrl = expr.getParameters().get(0).getConstant().primitiveValue(); - SourcedChildDefinitions childDefinitions = profileUtilities.getChildMap(sd, element.getElement()); + SourcedChildDefinitions childDefinitions = profileUtilities.getChildMap(sd, element.getElement(), true); for (ElementDefinition t : childDefinitions.getList()) { if (t.getPath().endsWith(".extension") && t.hasSliceName()) { StructureDefinition exsd = (t.getType() == null || t.getType().isEmpty() || t.getType().get(0).getProfile().isEmpty()) ? @@ -6666,7 +6666,7 @@ public class FHIRPathEngine { exsd = worker.fetchResource(StructureDefinition.class, exsd.getBaseDefinition(), exsd); } if (exsd != null && exsd.getUrl().equals(targetUrl)) { - if (profileUtilities.getChildMap(sd, t).getList().isEmpty()) { + if (profileUtilities.getChildMap(sd, t, false).getList().isEmpty()) { sd = exsd; } focus = new TypedElementDefinition(t); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java index 90b3d55ac..aabf040d2 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java @@ -99,7 +99,7 @@ public class ProfileDrivenRenderer extends ResourceRenderer { if (sd == null) return "unknown resource " +res.fhirType(); else { - SourcedChildDefinitions childDefs = context.getProfileUtilities().getChildMap(sd, ed); + SourcedChildDefinitions childDefs = context.getProfileUtilities().getChildMap(sd, ed, true); CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder("; "); for (NamedResourceWrapperList p : res.childrenInGroups()) { ElementDefinition pDefn = getElementDefinition(childDefs, p); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/TerminologyCacheManager.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/TerminologyCacheManager.java index daa378a5b..1428815f1 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/TerminologyCacheManager.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/TerminologyCacheManager.java @@ -9,6 +9,7 @@ import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Arrays; import java.util.Date; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -78,7 +79,7 @@ public class TerminologyCacheManager { try { System.out.println("Initialise terminology cache from "+source); - HTTPResult res = ManagedWebAccess.get(source+"?nocache=" + System.currentTimeMillis()); + HTTPResult res = ManagedWebAccess.get(Arrays.asList("web"), source+"?nocache=" + System.currentTimeMillis()); res.checkThrowException(); unzip(new ByteArrayInputStream(res.getContent()), cacheFolder); } catch (Exception e) { @@ -148,7 +149,7 @@ public class TerminologyCacheManager { // post it to String url = "https://tx.fhir.org/post/tx-cache/"+ghOrg+"/"+ghRepo+"/"+ghBranch+".zip"; System.out.println("Sending tx-cache to "+url+" ("+Utilities.describeSize(bs.toByteArray().length)+")"); - HTTPResult res = ManagedWebAccess.accessor() + HTTPResult res = ManagedWebAccess.accessor(Arrays.asList("web")) .withBasicAuth(token.substring(0, token.indexOf(':')), token.substring(token.indexOf(':') + 1)) .put(url, bs.toByteArray(), null, "application/zip"); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/client/ITerminologyClient.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/client/ITerminologyClient.java index 2be9473c0..172b9349e 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/client/ITerminologyClient.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/client/ITerminologyClient.java @@ -60,6 +60,7 @@ public interface ITerminologyClient { ITerminologyClient setLogger(ToolingClientLogger txLog) throws FHIRException; int getRetryCount() throws FHIRException; ITerminologyClient setRetryCount(int retryCount) throws FHIRException; + CapabilityStatement getCapabilitiesStatement() throws FHIRException; CapabilityStatement getCapabilitiesStatementQuick() throws FHIRException; Parameters lookupCode(Map params) throws FHIRException; Parameters lookupCode(Parameters params) throws FHIRException; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/client/TerminologyClientR5.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/client/TerminologyClientR5.java index b0f2f7b46..fd859b0e9 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/client/TerminologyClientR5.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/client/TerminologyClientR5.java @@ -165,6 +165,11 @@ public class TerminologyClientR5 implements ITerminologyClient { return client.getCapabilitiesStatementQuick(); } + @Override + public CapabilityStatement getCapabilitiesStatement() { + return client.getCapabilitiesStatement(); + } + @Override public Parameters lookupCode(Map params) { return client.lookupCode(params); 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 2445a23d5..97e1f1158 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 @@ -3,6 +3,7 @@ package org.hl7.fhir.r5.test.utils; import org.apache.commons.codec.binary.Base64; import org.apache.commons.lang3.StringUtils; import org.hl7.fhir.exceptions.FHIRException; +import org.hl7.fhir.r5.model.Constants; import org.hl7.fhir.utilities.*; import org.hl7.fhir.utilities.filesystem.CSFile; import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; @@ -27,6 +28,7 @@ import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import java.io.*; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -34,12 +36,51 @@ public class CompareUtilities extends BaseTestingUtilities { private static final boolean SHOW_DIFF = false; private JsonObject externals; + private Map variables; + private boolean patternMode; + + public CompareUtilities() { + super(); + this.variables = new HashMap(); + } + + public CompareUtilities(JsonObject externals) { + super(); + this.externals = externals; + this.variables = new HashMap(); + } + + public CompareUtilities(JsonObject externals, Map variables) { + super(); + this.externals = externals; + this.variables = variables; + } + + /** + * in pattern mode, the comparison is only looking to find the expected properties. anything else is ignored + * @return + */ + public boolean isPatternMode() { + return patternMode; + } + + public CompareUtilities setPatternMode(boolean patternMode) { + this.patternMode = patternMode; + return this; + } public String createNotEqualMessage(String id, final String message, final String expected, final String actual) { + if (patternMode) { return new StringBuilder() - .append(message).append('\n') - .append("Expected:").append(presentExpected(expected)).append(" for "+id).append('\n') + .append(message).append(". ") + .append("Expected:").append(presentExpected(expected)).append(" for "+id).append(". ") .append("Actual :").append("\""+actual+"\"").toString(); + } else { + return new StringBuilder() + .append(message).append('\n') + .append("Expected:").append(presentExpected(expected)).append(" for "+id).append('\n') + .append("Actual :").append("\""+actual+"\"").toString(); + } } private String presentExpected(String expected) { @@ -64,8 +105,13 @@ public class CompareUtilities extends BaseTestingUtilities { switch (expected) { case "$$" : return "$$"; case "$instant$": return "\"An Instant\""; + case "$date$": return "\"A date\""; case "$uuid$": return "\"A Uuid\""; + case "$string$": return "\"A string\""; case "$id$": return "\"An Id\""; + case "$url$": return "\"A URL\""; + case "$token$": return "\"A Token\""; + case "$version$": return variables.containsKey("version") ? variables.get("version") : "(anything)"; default: return "Unhandled template: "+expected; } } @@ -74,15 +120,13 @@ public class CompareUtilities extends BaseTestingUtilities { } } - public static String checkXMLIsSame(String id, InputStream expected, InputStream actual) throws Exception { - CompareUtilities self = new CompareUtilities(); - String result = self.compareXml(id, expected, actual); + public String checkXMLIsSame(String id, InputStream expected, InputStream actual) throws Exception { + String result = compareXml(id, expected, actual); return result; } - public static String checkXMLIsSame(String id, String expected, String actual) throws Exception { - CompareUtilities self = new CompareUtilities(); - String result = self.compareXml(id, expected, actual); + public String checkXMLIsSame(String id, String expected, String actual) throws Exception { + String result = compareXml(id, expected, actual); if (result != null && SHOW_DIFF) { String diff = getDiffTool(); if (diff != null && ManagedFileAccess.file(diff).exists() || Utilities.isToken(diff)) { @@ -92,7 +136,7 @@ public class CompareUtilities extends BaseTestingUtilities { return result; } - private static String getDiffTool() throws IOException { + private String getDiffTool() throws IOException { if (FhirSettings.hasDiffToolPath()) { return FhirSettings.getDiffToolPath(); } else if (System.getenv("ProgramFiles") != null) { @@ -219,14 +263,12 @@ public class CompareUtilities extends BaseTestingUtilities { return builder.parse(fn); } - public static String checkJsonSrcIsSame(String id, String expected, String actual, JsonObject externals) throws FileNotFoundException, IOException { - return checkJsonSrcIsSame(id, expected, actual, true, externals); + public String checkJsonSrcIsSame(String id, String expected, String actual) throws FileNotFoundException, IOException { + return checkJsonSrcIsSame(id, expected, actual, true); } - public static String checkJsonSrcIsSame(String id, String expectedString, String actualString, boolean showDiff, JsonObject externals) throws FileNotFoundException, IOException { - CompareUtilities self = new CompareUtilities(); - self.externals = externals; - String result = self.compareJsonSrc(id, expectedString, actualString); + public String checkJsonSrcIsSame(String id, String expectedString, String actualString, boolean showDiff) throws FileNotFoundException, IOException { + String result = compareJsonSrc(id, expectedString, actualString); if (result != null && SHOW_DIFF && showDiff) { String diff = null; if (System.getProperty("os.name").contains("Linux")) @@ -259,9 +301,8 @@ public class CompareUtilities extends BaseTestingUtilities { return result; } - public static String checkJsonIsSame(String id, String expected, String actual) throws FileNotFoundException, IOException { - CompareUtilities self = new CompareUtilities(); - String result = self.compareJson(id, expected, actual); + public String checkJsonIsSame(String id, String expected, String actual) throws FileNotFoundException, IOException { + String result = compareJson(id, expected, actual); if (result != null && SHOW_DIFF) { String diff = Utilities.path(System.getenv("ProgramFiles(X86)"), "WinMerge", "WinMergeU.exe"); List command = new ArrayList(); @@ -294,16 +335,17 @@ public class CompareUtilities extends BaseTestingUtilities { String n = en.getName(); if (!n.equals("fhir_comments")) { if (expectedJsonObject.has(n)) { - String s = compareNodes(id, path + '.' + n, expectedJsonObject.get(n), en.getValue(), countOnlys.contains(n)); + String s = compareNodes(id, path + '.' + n, expectedJsonObject.get(n), en.getValue(), countOnlys.contains(n), n, actualJsonObject); if (!Utilities.noString(s)) return s; - } else - return "properties differ at " + path + ": missing property " + n; + } else if (!patternMode) { + return "properties differ at " + path + ": unexpected property " + n; + } } } for (JsonProperty en : expectedJsonObject.getProperties()) { String n = en.getName(); - if (!n.equals("fhir_comments") && !n.equals("$optional$") && !optionals.contains(n)) { + if (!n.equals("fhir_comments") && !isOptional(n, optionals)) { if (!actualJsonObject.has(n) && !allOptional(en.getValue())) return "properties differ at " + path + ": missing property " + n; } @@ -311,6 +353,10 @@ public class CompareUtilities extends BaseTestingUtilities { return null; } + private boolean isOptional(String n, List optionals) { + return n.equals("$optional$") || optionals.contains("*") || optionals.contains(n); + } + private boolean allOptional(JsonElement value) { if (value.isJsonArray()) { JsonArray a = value.asJsonArray(); @@ -352,7 +398,7 @@ public class CompareUtilities extends BaseTestingUtilities { return res; } - private String compareNodes(String id, String path, JsonElement expectedJsonElement, JsonElement actualJsonElement, boolean countOnly) { + private String compareNodes(String id, String path, JsonElement expectedJsonElement, JsonElement actualJsonElement, boolean countOnly, String name, JsonObject parent) { if (!(expectedJsonElement instanceof JsonPrimitive && actualJsonElement instanceof JsonPrimitive)) { if (actualJsonElement.getClass() != expectedJsonElement.getClass()) { return createNotEqualMessage(id, "properties differ at " + path, expectedJsonElement.getClass().getName(), actualJsonElement.getClass().getName()); @@ -394,30 +440,51 @@ public class CompareUtilities extends BaseTestingUtilities { return createNotEqualMessage(id, "array item count differs at " + path, Integer.toString(es), Integer.toString(as)); } } else { - int expectedMin = countExpectedMin(expectedArray); - int oc = optionalCount(expectedArray); + int expectedMin = countExpectedMin(expectedArray, name, parent); + int oc = optionalCount(expectedArray, name, parent); + - if (as > es || as < expectedMin) - return createNotEqualMessage(id, "array item count differs at " + path, Integer.toString(es), Integer.toString(as)); - int c = 0; - for (int i = 0; i < es; i++) { - if (c >= as) { - if (i >= es - oc && isOptional(expectedArray.get(i))) { - return null; // this is OK - } else { - return "One or more array items did not match at "+path+" starting at index "+i; + if (patternMode) { + int c = 0; + for (int i = 0; i < expectedArray.size(); i++) { + String s = "Doesn't exist"; + CommaSeparatedStringBuilder cs = new CommaSeparatedStringBuilder("\r\n"); + cs.append(""); + while (s != null && c < actualArray.size()) { + s = compareNodes(id, path + "[" + Integer.toString(i) + "]", expectedArray.get(i), actualArray.get(c), false, null, null); + if (s != null) { + cs.append(" "+s); + } + c++; + } + if (s != null) { + return "The expected item at "+path+" at index "+i+" was not found: "+cs.toString(); } } - String s = compareNodes(id, path + "[" + Integer.toString(i) + "]", expectedArray.get(i), actualArray.get(c), false); - if (!Utilities.noString(s) && !isOptional(expectedArray.get(i))) { - return s; + } else { + if (as > es || as < expectedMin) { + return createNotEqualMessage(id, "array item count differs at " + path, Integer.toString(es), Integer.toString(as)); } - if (Utilities.noString(s)) { - c++; + int c = 0; + for (int i = 0; i < es; i++) { + if (c >= as) { + if (i >= es - oc && isOptional(expectedArray.get(i), name, parent)) { + return null; // this is OK + } else { + return "One or more array items did not match at "+path+" starting at index "+i; + } + } + String s = compareNodes(id, path + "[" + Integer.toString(i) + "]", expectedArray.get(i), actualArray.get(c), false, null, null); + if (!Utilities.noString(s) && !isOptional(expectedArray.get(i), name, parent)) { + return s; + } + if (Utilities.noString(s)) { + c++; + } + } + if (c < as) { + return "Unexpected Node found in array at '"+path+"' at index "+c; } - } - if (c < as) { - return "Unexpected Node found in array at '"+path+"' at index "+c; } } } else @@ -425,7 +492,7 @@ public class CompareUtilities extends BaseTestingUtilities { return null; } - private int optionalCount(JsonArray arr) { + private int optionalCount(JsonArray arr, String name, JsonObject parent) { int c = 0; for (JsonElement e : arr) { if (e.isJsonObject()) { @@ -438,14 +505,14 @@ public class CompareUtilities extends BaseTestingUtilities { return c; } - private boolean isOptional(JsonElement e) { + private boolean isOptional(JsonElement e, String name, JsonObject parent) { return e.isJsonObject() && e.asJsonObject().has("$optional$"); } - private int countExpectedMin(JsonArray array) { + private int countExpectedMin(JsonArray array, String name, JsonObject parent) { int count = array.size(); for (JsonElement e : array) { - if (isOptional(e)) { + if (isOptional(e, name, parent)) { count--; } } @@ -485,8 +552,13 @@ public class CompareUtilities extends BaseTestingUtilities { switch (expectedJsonString) { case "$$" : return true; case "$instant$": return actualJsonString.matches("([0-9]([0-9]([0-9][1-9]|[1-9]0)|[1-9]00)|[1-9]000)-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])T([01][0-9]|2[0-3]):[0-5][0-9]:([0-5][0-9]|60)(\\.[0-9]{1,9})?(Z|(\\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00))"); + case "$date$": return actualJsonString.matches("([0-9]([0-9]([0-9][1-9]|[1-9]0)|[1-9]00)|[1-9]000)-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])(T([01][0-9]|2[0-3]):[0-5][0-9]:([0-5][0-9]|60)(\\.[0-9]{1,9})?(Z|(\\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00)))?"); case "$uuid$": return actualJsonString.matches("urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"); + case "$string$": return actualJsonString.equals(actualJsonString.trim()); case "$id$": return actualJsonString.matches("[A-Za-z0-9\\-\\.]{1,64}"); + case "$url$": return actualJsonString.matches("(https?://|www\\.)[-a-zA-Z0-9+&@#/%?=~_|!:.;]*[-a-zA-Z0-9+&@#/%=~_|]"); + case "$token$": return actualJsonString.matches("[0-9a-zA-Z_][0-9a-zA-Z_\\.\\-]*"); + case "$version$": return matchesVariable(actualJsonString, "version"); default: throw new Error("Unhandled template: "+expectedJsonString); } @@ -496,6 +568,14 @@ public class CompareUtilities extends BaseTestingUtilities { } } + private boolean matchesVariable(String value, String name) { + if (variables.containsKey(name)) { + return value.equals(variables.get(name)); + } else { + return true; + } + } + private List readChoices(String s) { List list = new ArrayList<>(); for (String p : s.split("\\|")) { @@ -504,13 +584,12 @@ public class CompareUtilities extends BaseTestingUtilities { return list; } - public static String checkTextIsSame(String id, String expected, String actual) throws FileNotFoundException, IOException { + public String checkTextIsSame(String id, String expected, String actual) throws FileNotFoundException, IOException { return checkTextIsSame(id, expected, actual, true); } - public static String checkTextIsSame(String id, String expectedString, String actualString, boolean showDiff) throws FileNotFoundException, IOException { - CompareUtilities self = new CompareUtilities(); - String result = self.compareText(id, expectedString, actualString); + public String checkTextIsSame(String id, String expectedString, String actualString, boolean showDiff) throws FileNotFoundException, IOException { + String result = compareText(id, expectedString, actualString); if (result != null && SHOW_DIFF && showDiff) { String diff = null; if (System.getProperty("os.name").contains("Linux")) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/structuremap/StructureMapUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/structuremap/StructureMapUtilities.java index 0cabfd16b..f22539dd0 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/structuremap/StructureMapUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/structuremap/StructureMapUtilities.java @@ -2700,7 +2700,7 @@ public class StructureMapUtilities { private void addChildMappings(StringBuilder b, String id, String indent, StructureDefinition sd, ElementDefinition ed, boolean inner) throws DefinitionException { boolean first = true; - List children = profileUtilities.getChildMap(sd, ed).getList(); + List children = profileUtilities.getChildMap(sd, ed, true).getList(); for (ElementDefinition child : children) { if (first && inner) { b.append(" then {\r\n"); diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/elementmodel/LanguageUtilsTest.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/elementmodel/LanguageUtilsTest.java index 631731b27..4825f225e 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/elementmodel/LanguageUtilsTest.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/elementmodel/LanguageUtilsTest.java @@ -47,7 +47,7 @@ class LanguageUtilsTest implements ResourceLoaderTests { .lines() .collect(Collectors.joining("\n")); - String msg = CompareUtilities.checkJsonSrcIsSame("", generatedResource.toString(),text, null); + String msg = new CompareUtilities().checkJsonSrcIsSame("", generatedResource.toString(),text); Assertions.assertNull(msg); } diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/sql/SQLOnFhirTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/sql/SQLOnFhirTests.java index d650980fb..1d4d60c52 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/sql/SQLOnFhirTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/sql/SQLOnFhirTests.java @@ -138,7 +138,7 @@ public class SQLOnFhirTests { // sortResults(rows); String expS = JsonParser.compose(exp, true); String rowS = JsonParser.compose(rows, true); - String c = CompareUtilities.checkJsonSrcIsSame(name, expS, rowS, null); + String c = new CompareUtilities().checkJsonSrcIsSame(name, expS, rowS); Assertions.assertNull(c, c); } else if (test.testCase.has("expectCount")) { Assertions.assertEquals(test.testCase.asInteger("expectCount"), results.size()); diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/GraphQLEngineTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/GraphQLEngineTests.java index ecba23c02..8e01e5d8d 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/GraphQLEngineTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/GraphQLEngineTests.java @@ -98,7 +98,7 @@ public class GraphQLEngineTests implements IGraphQLStorageServices { IOUtils.copy(CompareUtilities.loadTestResourceStream("r5", "graphql", source), ManagedFileAccess.outStream(CompareUtilities.tempFile("graphql", source))); IOUtils.copy(CompareUtilities.loadTestResourceStream("r5", "graphql", output), ManagedFileAccess.outStream(CompareUtilities.tempFile("graphql", output))); TextFile.stringToFile(str.toString(), CompareUtilities.tempFile("graphql", output+".out")); - msg = CompareUtilities.checkJsonIsSame(id, CompareUtilities.tempFile("graphql", output), CompareUtilities.tempFile("graphql", output+".out")); + msg = new CompareUtilities().checkJsonIsSame(id, CompareUtilities.tempFile("graphql", output), CompareUtilities.tempFile("graphql", output+".out")); Assertions.assertTrue(Utilities.noString(msg), msg); } else diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/NarrativeGenerationTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/NarrativeGenerationTests.java index cab59327e..82fdb3e78 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/NarrativeGenerationTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/NarrativeGenerationTests.java @@ -279,7 +279,7 @@ public class NarrativeGenerationTests { String actualFileName = CompareUtilities.tempFile("narrative", test.getId() + ".html"); TextFile.stringToFile(expected, expectedFileName); TextFile.stringToFile(actual, actualFileName); - String msg = CompareUtilities.checkXMLIsSame(id, expectedFileName, actualFileName); + String msg = new CompareUtilities().checkXMLIsSame(id, expectedFileName, actualFileName); Assertions.assertTrue(msg == null, "Output does not match expected: "+msg); String disp = RendererFactory.factory(source, rc).buildSummary(ResourceWrapper.forResource(rc.getContextUtilities(), source)); @@ -289,7 +289,7 @@ public class NarrativeGenerationTests { actualFileName = CompareUtilities.tempFile("narrative", test.getId() + ".txt"); TextFile.stringToFile(expected, expectedFileName); TextFile.stringToFile(actual, actualFileName); - msg = CompareUtilities.checkTextIsSame(id, expected, actual); + msg = new CompareUtilities().checkTextIsSame(id, expected, actual); Assertions.assertTrue(msg == null, "Summary Output does not match expected: "+msg); // diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/ParsingTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/ParsingTests.java index b34987537..ca7d8ebbe 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/ParsingTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/ParsingTests.java @@ -58,7 +58,7 @@ public class ParsingTests { r = new XmlParser().parse(b); b = new JsonParser().setOutputStyle(OutputStyle.PRETTY).composeBytes(r); String output = new String(b); - String msg = CompareUtilities.checkJsonSrcIsSame(name, src, output, null); + String msg = new CompareUtilities().checkJsonSrcIsSame(name, src, output); Assertions.assertTrue(msg == null, msg); } diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/ResourceToElementTest.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/ResourceToElementTest.java index 1051b07a4..fa30c96e5 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/ResourceToElementTest.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/ResourceToElementTest.java @@ -40,7 +40,7 @@ public class ResourceToElementTest { Element e = p.parse(res); new org.hl7.fhir.r5.elementmodel.XmlParser(ctxt).compose(e, ManagedFileAccess.outStream(src), OutputStyle.PRETTY, null); new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(ManagedFileAccess.outStream(dst), res); - String msg = CompareUtilities.checkXMLIsSame(filename, src, dst); + String msg = new CompareUtilities().checkXMLIsSame(filename, src, dst); Assertions.assertNull(msg); } diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/VocabTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/VocabTests.java index 78d3fdbca..ef160a77b 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/VocabTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/VocabTests.java @@ -157,7 +157,7 @@ public class VocabTests { String actualFileName = CompareUtilities.tempFile("vocab", test.getId() + ".actual.html"); TextFile.stringToFile(expected, expectedFileName); TextFile.stringToFile(actual, actualFileName); - String msg = CompareUtilities.checkXMLIsSame(test.id, expectedFileName, actualFileName); + String msg = new CompareUtilities().checkXMLIsSame(test.id, expectedFileName, actualFileName); Assertions.assertTrue(msg == null, "Output does not match expected: "+msg); } else { Assertions.fail("Expansion Failed: "+outcome.getError()); diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/profiles/GeneratedPEModelTest.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/profiles/GeneratedPEModelTest.java index d85d2d448..61b14c08a 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/profiles/GeneratedPEModelTest.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/profiles/GeneratedPEModelTest.java @@ -68,7 +68,7 @@ public class GeneratedPEModelTest { Observation tgt = tp.build(ctxt); new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(ManagedFileAccess.outStream(Utilities.path("[tmp]", "pe-instance-gen.xml")), tgt); - String msg = CompareUtilities.checkXMLIsSame("PEGEN", TestingUtilities.loadTestResourceStream("r5", "profiles", "pe-instance.xml"), ManagedFileAccess.inStream(Utilities.path("[tmp]", "pe-instance-gen.xml"))); + String msg = new CompareUtilities().checkXMLIsSame("PEGEN", TestingUtilities.loadTestResourceStream("r5", "profiles", "pe-instance.xml"), ManagedFileAccess.inStream(Utilities.path("[tmp]", "pe-instance-gen.xml"))); Assertions.assertNull(msg, msg); } diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/profiles/PETests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/profiles/PETests.java index eed237ad0..34a18f653 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/profiles/PETests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/profiles/PETests.java @@ -422,7 +422,7 @@ public class PETests { private void checkGeneratedJava(String name) throws FileNotFoundException, IOException { String actual = Utilities.normalize(TextFile.fileToString(Utilities.path("[tmp]", "codegen", name+".java"))); String expected = Utilities.normalize(TestingUtilities.loadTestResource("r5", "profiles", name+".java")); - String msg = CompareUtilities.checkTextIsSame(name, expected, actual); + String msg = new CompareUtilities().checkTextIsSame(name, expected, actual); if (msg != null) { Assertions.fail("Generated code for "+name+" is different: "+msg); } diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/utils/CompareUtilitiesTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/utils/CompareUtilitiesTests.java index bb11b9758..03edba360 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/utils/CompareUtilitiesTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/utils/CompareUtilitiesTests.java @@ -59,7 +59,7 @@ public class CompareUtilitiesTests implements ResourceLoaderTests { InputStream expectedXMLStream = classLoader.getResourceAsStream(expectedXMLPath); InputStream actualXMLStream = classLoader.getResourceAsStream(actualXMLPath); - final String actualOutput = CompareUtilities.checkXMLIsSame(expectedFileName, expectedXMLStream, actualXMLStream); + final String actualOutput = new CompareUtilities().checkXMLIsSame(expectedFileName, expectedXMLStream, actualXMLStream); if (expectedOutputFileName == null) { assertNull(actualOutput); @@ -91,7 +91,7 @@ public class CompareUtilitiesTests implements ResourceLoaderTests { final String expectedJSONPath = ROOT_JSON_TEST_PATH.resolve(expectedFileName).toString(); final String actualJSONPath = ROOT_JSON_TEST_PATH.resolve(actualFileName).toString(); - final String actualOutput = CompareUtilities.checkJsonSrcIsSame(expectedFileName, getResourceAsString(expectedJSONPath), getResourceAsString(actualJSONPath), false, null); + final String actualOutput = new CompareUtilities().checkJsonSrcIsSame(expectedFileName, getResourceAsString(expectedJSONPath), getResourceAsString(actualJSONPath), false); if (expectedOutputFileName == null) { assertNull(actualOutput); } else { diff --git a/org.hl7.fhir.r5/src/test/resources/testUtilities/json/actualExtraProperty.json.error b/org.hl7.fhir.r5/src/test/resources/testUtilities/json/actualExtraProperty.json.error index dc127601c..8bca7ed5f 100644 --- a/org.hl7.fhir.r5/src/test/resources/testUtilities/json/actualExtraProperty.json.error +++ b/org.hl7.fhir.r5/src/test/resources/testUtilities/json/actualExtraProperty.json.error @@ -1 +1 @@ -properties differ at : missing property unexpectedProperty \ No newline at end of file +properties differ at : unexpected property unexpectedProperty \ No newline at end of file diff --git a/org.hl7.fhir.report/pom.xml b/org.hl7.fhir.report/pom.xml index 6d07fd2f4..e7d848df7 100644 --- a/org.hl7.fhir.report/pom.xml +++ b/org.hl7.fhir.report/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 6.4.1-SNAPSHOT + 6.4.2-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.utilities/pom.xml b/org.hl7.fhir.utilities/pom.xml index f03529e52..09b26fb2c 100644 --- a/org.hl7.fhir.utilities/pom.xml +++ b/org.hl7.fhir.utilities/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 6.4.1-SNAPSHOT + 6.4.2-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/ManagedFhirWebAccessor.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/ManagedFhirWebAccessor.java index b12c84175..cdc1989e1 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/ManagedFhirWebAccessor.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/ManagedFhirWebAccessor.java @@ -9,6 +9,7 @@ import org.hl7.fhir.utilities.settings.ServerDetailsPOJO; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -45,7 +46,7 @@ public class ManagedFhirWebAccessor extends ManagedWebAccessorBase serverAuthDetails) { - super(userAgent, serverAuthDetails); + super(Arrays.asList("fhir"), userAgent, serverAuthDetails); this.timeout = 5000; this.timeoutUnit = TimeUnit.MILLISECONDS; } @@ -88,7 +89,7 @@ public class ManagedFhirWebAccessor extends ManagedWebAccessorBase headers) throws IOException; - HTTPResult post(String url, byte[] bytes, String contentType, String accept, Map headers) throws IOException; - HTTPResult put(String url, byte[] bytes, String contentType, String accept, Map headers) throws IOException; + HTTPResult get(Iterable serverTypes, String url, String accept, Map headers) throws IOException; + HTTPResult post(Iterable serverTypes, String url, byte[] bytes, String contentType, String accept, Map headers) throws IOException; + HTTPResult put(Iterable serverTypes, String url, byte[] bytes, String contentType, String accept, Map headers) throws IOException; } public interface IFhirWebAccessor { @@ -104,28 +104,28 @@ public class ManagedWebAccess { ManagedWebAccess.userAgent = userAgent; } - public static ManagedWebAccessor accessor() { - return new ManagedWebAccessor(userAgent, serverAuthDetails); + public static ManagedWebAccessor accessor(Iterable serverTypes) { + return new ManagedWebAccessor(serverTypes, userAgent, serverAuthDetails); } public static ManagedFhirWebAccessor fhirAccessor() { return new ManagedFhirWebAccessor(userAgent, serverAuthDetails); } - public static HTTPResult get(String url) throws IOException { - return accessor().get(url); + public static HTTPResult get(Iterable serverTypes, String url) throws IOException { + return accessor(serverTypes).get(url); } - public static HTTPResult get(String url, String accept) throws IOException { - return accessor().get(url, accept); + public static HTTPResult get(Iterable serverTypes, String url, String accept) throws IOException { + return accessor(serverTypes).get(url, accept); } - public static HTTPResult post(String url, byte[] content, String contentType, String accept) throws IOException { - return accessor().post(url, content, contentType, accept); + public static HTTPResult post(Iterable serverTypes, String url, byte[] content, String contentType, String accept) throws IOException { + return accessor(serverTypes).post(url, content, contentType, accept); } - public static HTTPResult put(String url, byte[] content, String contentType, String accept) throws IOException { - return accessor().put(url, content, contentType, accept); + public static HTTPResult put(Iterable serverTypes, String url, byte[] content, String contentType, String accept) throws IOException { + return accessor(serverTypes).put(url, content, contentType, accept); } public static HTTPResult httpCall(HTTPRequest httpRequest) throws IOException { @@ -136,15 +136,13 @@ public class ManagedWebAccess { setAccessPolicy(FhirSettings.isProhibitNetworkAccess() ? WebAccessPolicy.PROHIBITED : WebAccessPolicy.DIRECT); setUserAgent("hapi-fhir-tooling-client"); serverAuthDetails = new ArrayList<>(); - serverAuthDetails.addAll(FhirSettings.getPackageServers()); - serverAuthDetails.addAll(FhirSettings.getTerminologyServers()); + serverAuthDetails.addAll(FhirSettings.getServers()); } public static void loadFromFHIRSettings(FhirSettings settings) { setAccessPolicy(settings.isProhibitNetworkAccess() ? WebAccessPolicy.PROHIBITED : WebAccessPolicy.DIRECT); setUserAgent("hapi-fhir-tooling-client"); serverAuthDetails = new ArrayList<>(); - serverAuthDetails.addAll(settings.getPackageServers()); - serverAuthDetails.addAll(settings.getTerminologyServers()); + serverAuthDetails.addAll(settings.getServers()); } } \ No newline at end of file diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/ManagedWebAccessUtils.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/ManagedWebAccessUtils.java index a97353633..f37797314 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/ManagedWebAccessUtils.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/ManagedWebAccessUtils.java @@ -4,14 +4,21 @@ import org.hl7.fhir.utilities.settings.ServerDetailsPOJO; public class ManagedWebAccessUtils { - public static ServerDetailsPOJO getServer(String url, Iterable serverAuthDetails) { + public static ServerDetailsPOJO getServer(Iterable serverTypes, String url, Iterable serverAuthDetails) { if (serverAuthDetails != null) { - for (ServerDetailsPOJO t : serverAuthDetails) { - if (url.startsWith(t.getUrl())) { - return t; + for (ServerDetailsPOJO serverDetails : serverAuthDetails) { + for (String serverType : serverTypes) { + if (url.startsWith(serverDetails.getUrl()) && typesMatch(serverType, serverDetails.getType())) { + return serverDetails; + } } } } return null; } + + private static boolean typesMatch(String criteria, String value) { + return criteria == null || value == null || criteria.equals(value); + } + } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/ManagedWebAccessor.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/ManagedWebAccessor.java index 4c364a2f5..10fdb5d1e 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/ManagedWebAccessor.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/ManagedWebAccessor.java @@ -14,8 +14,8 @@ import org.hl7.fhir.utilities.settings.ServerDetailsPOJO; */ public class ManagedWebAccessor extends ManagedWebAccessorBase { - public ManagedWebAccessor(String userAgent, List serverAuthDetails) { - super(userAgent, serverAuthDetails); + public ManagedWebAccessor(Iterable serverTypes, String userAgent, List serverAuthDetails) { + super(serverTypes, userAgent, serverAuthDetails); } private Map newHeaders() { @@ -66,7 +66,7 @@ public class ManagedWebAccessor extends ManagedWebAccessorBase> { + @Getter + private final Iterable serverTypes; + @Getter private final String userAgent; @Getter @@ -24,7 +27,8 @@ public abstract class ManagedWebAccessorBase @Getter private final Map headers = new HashMap<>(); - public ManagedWebAccessorBase(String userAgent, List serverAuthDetails) { + public ManagedWebAccessorBase(Iterable serverTypes, String userAgent, List serverAuthDetails) { + this.serverTypes = serverTypes; this.userAgent = userAgent; this.serverAuthDetails = serverAuthDetails; } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java index e5c029607..c36b67897 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java @@ -589,6 +589,7 @@ public class I18nConstants { public static final String SD_ELEMENT_FIXED_WRONG_TYPE = "SD_ELEMENT_FIXED_WRONG_TYPE"; public static final String SD_ELEMENT_NOT_IN_CONSTRAINT = "SD_ELEMENT_NOT_IN_CONSTRAINT"; public static final String SD_ELEMENT_PATTERN_WRONG_TYPE = "SD_ELEMENT_PATTERN_WRONG_TYPE"; + public static final String SD_ELEMENT_PATTERN_NO_FIXED = "SD_ELEMENT_PATTERN_NO_FIXED"; public static final String SD_ELEMENT_REASON_DERIVED = "SD_ELEMENT_REASON_DERIVED"; public static final String SD_EXTENSION_URL_MISMATCH = "SD_EXTENSION_URL_MISMATCH"; public static final String SD_EXTENSION_URL_MISSING = "SD_EXTENSION_URL_MISSING"; diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/json/JsonTrackingParser.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/json/JsonTrackingParser.java index 893aba96c..aa46b74e0 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/json/JsonTrackingParser.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/json/JsonTrackingParser.java @@ -2,34 +2,34 @@ package org.hl7.fhir.utilities.json; import java.io.File; -/* - Copyright (c) 2011+, HL7, Inc. - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, - are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of HL7 nor the names of its contributors may be used to - endorse or promote products derived from this software without specific - prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. - - */ +/* + Copyright (c) 2011+, HL7, Inc. + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of HL7 nor the names of its contributors may be used to + endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + */ @@ -37,6 +37,7 @@ import java.io.IOException; import java.io.InputStream; import java.math.BigDecimal; import java.nio.charset.StandardCharsets; +import java.util.Arrays; import java.util.Map; import java.util.Stack; @@ -724,13 +725,13 @@ public class JsonTrackingParser { } public static JsonObject fetchJson(String source) throws IOException { - HTTPResult res = ManagedWebAccess.get(source+"?nocache=" + System.currentTimeMillis(), "application/json, application/fhir+json"); + HTTPResult res = ManagedWebAccess.get(Arrays.asList("web"), source+"?nocache=" + System.currentTimeMillis(), "application/json, application/fhir+json"); res.checkThrowException(); return parseJson(res.getContent()); } public static JsonArray fetchJsonArray(String source) throws IOException { - HTTPResult res = ManagedWebAccess.get(source+"?nocache=" + System.currentTimeMillis(), "application/json, application/fhir+json"); + HTTPResult res = ManagedWebAccess.get(Arrays.asList("web"),source+"?nocache=" + System.currentTimeMillis(), "application/json, application/fhir+json"); res.checkThrowException(); return parseJsonArray(res.getContent()); } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/json/parser/JsonParser.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/json/parser/JsonParser.java index df6efedc3..ddd245065 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/json/parser/JsonParser.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/json/parser/JsonParser.java @@ -6,6 +6,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.StandardCharsets; +import java.util.Arrays; import java.util.List; import org.hl7.fhir.utilities.TextFile; @@ -692,7 +693,7 @@ public class JsonParser { private static byte[] fetch(String source) throws IOException { String murl = source.contains("?") ? source+"&nocache=" + System.currentTimeMillis() : source+"?nocache=" + System.currentTimeMillis(); - HTTPResult res = ManagedWebAccess.get(murl, "application/json, application/fhir+json"); + HTTPResult res = ManagedWebAccess.get(Arrays.asList("web"), murl, "application/json, application/fhir+json"); res.checkThrowException(); return res.getContent(); } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/FilesystemPackageCacheManager.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/FilesystemPackageCacheManager.java index e8eca8f80..1346def8e 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/FilesystemPackageCacheManager.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/FilesystemPackageCacheManager.java @@ -729,7 +729,7 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple private InputStream fetchFromUrlSpecific(String source, boolean optional) throws FHIRException { try { - HTTPResult res = ManagedWebAccess.get(source); + HTTPResult res = ManagedWebAccess.get(Arrays.asList("web"), source); res.checkThrowException(); return new ByteArrayInputStream(res.getContent()); } catch (Exception e) { @@ -862,8 +862,7 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple } private void loadFromBuildServer() throws IOException { - - HTTPResult res = ManagedWebAccess.get("https://build.fhir.org/ig/qas.json?nocache=" + System.currentTimeMillis()); + HTTPResult res = ManagedWebAccess.get(Arrays.asList("web"), "https://build.fhir.org/ig/qas.json?nocache=" + System.currentTimeMillis()); res.checkThrowException(); buildInfo = (JsonArray) JsonParser.parse(TextFile.bytesToString(res.getContent())); diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java index 54c8ee917..362757650 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java @@ -44,15 +44,7 @@ import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; +import java.util.*; import java.util.zip.Deflater; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -1480,7 +1472,7 @@ public class NpmPackage { } public static NpmPackage fromUrl(String source) throws IOException { - HTTPResult res = ManagedWebAccess.get(source+"?nocache=" + System.currentTimeMillis()); + HTTPResult res = ManagedWebAccess.get(Arrays.asList("npm-package", "fhir-package"), source+"?nocache=" + System.currentTimeMillis()); res.checkThrowException(); return fromPackage(new ByteArrayInputStream(res.getContent())); } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageClient.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageClient.java index 6f6feeb84..28a88cc9f 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageClient.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageClient.java @@ -8,11 +8,7 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.Instant; import java.time.format.DateTimeParseException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.Set; +import java.util.*; import javax.annotation.Nullable; @@ -175,11 +171,13 @@ public class PackageClient { } private InputStream fetchUrl(String source, String accept) throws IOException { - ManagedWebAccessor webAccessor = ManagedWebAccess.accessor(); + ManagedWebAccessor webAccessor = ManagedWebAccess.accessor(Arrays.asList("web")); if (server.getAuthenticationMode() == HTTPAuthenticationMode.TOKEN) { webAccessor.withToken(server.getToken()); } else if (server.getAuthenticationMode() == HTTPAuthenticationMode.BASIC) { webAccessor.withBasicAuth(server.getUsername(), server.getPassword()); + } else if (server.getAuthenticationMode() == HTTPAuthenticationMode.APIKEY) { + webAccessor.withApiKey(server.getApiKey()); } HTTPResult res = webAccessor.get(source, accept); res.checkThrowException(); diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageServer.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageServer.java index 7ad221a1f..896126bd9 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageServer.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageServer.java @@ -7,7 +7,6 @@ import java.util.stream.Collectors; import javax.annotation.Nullable; import org.hl7.fhir.utilities.http.HTTPAuthenticationMode; -import org.hl7.fhir.utilities.http.SimpleHTTPClient; import org.hl7.fhir.utilities.settings.FhirSettings; import org.hl7.fhir.utilities.settings.ServerDetailsPOJO; @@ -27,10 +26,11 @@ public class PackageServer { serverType = PackageServerType.FHIR; } + @Getter private String url; @Getter - private HTTPAuthenticationMode authenticationMode; + private HTTPAuthenticationMode authenticationMode; @Getter private PackageServerType serverType; @@ -43,9 +43,11 @@ public class PackageServer { @Getter private String token; - public String getUrl() { - return url; - } + + @Getter + private String apiKey; + + public static final String PRIMARY_SERVER = "https://packages.fhir.org"; public static final String SECONDARY_SERVER = "https://packages2.fhir.org/packages"; @@ -69,24 +71,54 @@ public class PackageServer { return new PackageServer(pojo.getUrl()) .withAuthenticationMode(getModeFromPOJO(pojo)) .withServerType( - pojo.getServerType() != null && pojo.getServerType().equalsIgnoreCase("npm") ? PackageServerType.NPM : PackageServerType.FHIR + getPackageServerType(pojo.getType()) ) .withUsername(pojo.getUsername()) .withPassword(pojo.getPassword()) - .withToken(pojo.getToken()); + .withToken(pojo.getToken()) + .withApiKey(pojo.getApikey()); + + } + + private static boolean isPackageServer(String serverType) { + if (serverType == null) { + return false; + } + if (serverType.equals("fhir-package")) { + return true; + } + if (serverType.equals("npm-package")) { + return true; + } + return false; + } + + private static PackageServerType getPackageServerType(String serverType) { + if (serverType == null) { + return null; + } + if (serverType.equals("fhir-package")) { + return PackageServerType.FHIR; + } + if (serverType.equals("npm-package")) { + return PackageServerType.NPM; + } + return null; } @Nullable private static HTTPAuthenticationMode getModeFromPOJO(ServerDetailsPOJO pojo) { if (pojo.getAuthenticationType().equalsIgnoreCase("basic")) return HTTPAuthenticationMode.BASIC; if (pojo.getAuthenticationType().equalsIgnoreCase("token")) return HTTPAuthenticationMode.TOKEN; + if (pojo.getAuthenticationType().equalsIgnoreCase("apikey")) return HTTPAuthenticationMode.APIKEY; return null; } public static List getConfiguredServers() { - return FhirSettings.getPackageServers().stream().map( - PackageServer::getPackageServerFromPOJO - ).collect(Collectors.toList()); + return FhirSettings.getServers().stream() + .filter(serverDetailsPOJO -> isPackageServer(serverDetailsPOJO.getType())) + .map(PackageServer::getPackageServerFromPOJO) + .collect(Collectors.toList()); } @Override @@ -101,6 +133,7 @@ public class PackageServer { packageServer.username = this.username; packageServer.password = this.password; packageServer.token = this.token; + packageServer.apiKey = this.apiKey; return packageServer; } @@ -133,4 +166,10 @@ public class PackageServer { packageServer.token = token; return packageServer; } + + public PackageServer withApiKey(String apiKey) { + PackageServer packageServer = this.copy(); + packageServer.apiKey = apiKey; + return packageServer; + } } \ 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 index 060ce2195..df38237fb 100644 --- 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 @@ -222,25 +222,17 @@ public class FhirSettings { public static boolean isIgnoreDefaultPackageServers() { getInstance(); - if (instance.fhirSettings.getPackageManagement() == null || instance.fhirSettings.getPackageManagement().getIgnoreDefaultServers() == null) { + if (instance.fhirSettings.getIgnoreDefaultPackageServers() == null) { return false; } - return instance.fhirSettings.getPackageManagement().getIgnoreDefaultServers(); + return instance.fhirSettings.getIgnoreDefaultPackageServers(); } - public static List getPackageServers() { + public static List getServers() { getInstance(); - if (instance.fhirSettings.getPackageManagement() == null) { + if (instance.fhirSettings.getServers() == null) { return Collections.emptyList(); } - return Arrays.asList(instance.fhirSettings.getPackageManagement().getServers().toArray(new ServerDetailsPOJO[]{})); - } - - public static List getTerminologyServers() { - getInstance(); - if (instance.fhirSettings.getTerminologyServers() == null) { - return Collections.emptyList(); - } - return Arrays.asList(instance.fhirSettings.getTerminologyServers().getServers().toArray(new ServerDetailsPOJO[]{})); + return Arrays.asList(instance.fhirSettings.getServers().toArray(new ServerDetailsPOJO[]{})); } } 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 index a88638e91..2f63d2123 100644 --- 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 @@ -1,5 +1,7 @@ package org.hl7.fhir.utilities.settings; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import lombok.AllArgsConstructor; @@ -39,8 +41,9 @@ public class FhirSettingsPOJO { private String txFhirDevelopment; private String txFhirLocal; - private PackageManagementPOJO packageManagement; - private TerminologyServersPOJO terminologyServers; + private Boolean ignoreDefaultPackageServers; + + private List servers; protected FhirSettingsPOJO() { apiKeys = null; @@ -53,8 +56,6 @@ public class FhirSettingsPOJO { txFhirProduction = TX_SERVER_PROD; txFhirDevelopment = TX_SERVER_DEV; txFhirLocal = TX_SERVER_LOCAL; - - packageManagement = null; - terminologyServers = null; + servers = new ArrayList<>(); } } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/settings/PackageManagementPOJO.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/settings/PackageManagementPOJO.java deleted file mode 100644 index 1275b710c..000000000 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/settings/PackageManagementPOJO.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.hl7.fhir.utilities.settings; - -import java.util.ArrayList; -import java.util.List; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.extern.jackson.Jacksonized; - -@Data -@Builder -@Jacksonized -@AllArgsConstructor -public class PackageManagementPOJO { - - private Boolean ignoreDefaultServers; - - private List servers; - - protected PackageManagementPOJO() { - ignoreDefaultServers = false; - servers = new ArrayList<>(); - } -} diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/settings/ServerDetailsPOJO.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/settings/ServerDetailsPOJO.java index 5d716bcfe..160d16c63 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/settings/ServerDetailsPOJO.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/settings/ServerDetailsPOJO.java @@ -10,14 +10,25 @@ import lombok.extern.jackson.Jacksonized; @Jacksonized @AllArgsConstructor public class ServerDetailsPOJO { - + String url; // possible values: none, basic, token, apikey String authenticationType; - // npm or fhir, because the FHIR npm usage varies a little bit from general NPM usage (change over time) - String serverType; + /** + * This helps clients use appropriate API endpoints for each server type. + *

+ * It can be of the following types: + *

    + *
  • web
  • + *
  • fhir
  • + *
  • npm-package
  • + *
  • fhir-package
  • + *
+ */ + + String type; String username; diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/settings/TerminologyServersPOJO.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/settings/TerminologyServersPOJO.java deleted file mode 100644 index 33cf0822b..000000000 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/settings/TerminologyServersPOJO.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.hl7.fhir.utilities.settings; - -import java.util.ArrayList; -import java.util.List; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.extern.jackson.Jacksonized; - -@Data -@Builder -@Jacksonized -@AllArgsConstructor -public class TerminologyServersPOJO { - - private List servers; - - protected TerminologyServersPOJO() { - servers = new ArrayList<>(); - } -} diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages.properties b/org.hl7.fhir.utilities/src/main/resources/Messages.properties index b4c87aeaa..4fb1dac7c 100644 --- a/org.hl7.fhir.utilities/src/main/resources/Messages.properties +++ b/org.hl7.fhir.utilities/src/main/resources/Messages.properties @@ -593,7 +593,8 @@ SD_ED_TYPE_PROFILE_WRONG_TYPE_one = The type {0} is not in the list of allowed t SD_ED_TYPE_PROFILE_WRONG_TYPE_other = The type {0} is not in the list of allowed types {1} in the profile {2} SD_ELEMENT_FIXED_WRONG_TYPE = The base element has a fixed type of ''{0}'', so this element must have a fixed value of the same type, not ''{1}'' SD_ELEMENT_NOT_IN_CONSTRAINT = The element definition for {1} has a property {0} which is not allowed in a profile -SD_ELEMENT_PATTERN_WRONG_TYPE = The base element has a pattern type of ''{0}'', so this element must have a pattern value of the same type, not ''{1}'' +SD_ELEMENT_PATTERN_WRONG_TYPE = The base element has a pattern type of ''{0}'', so this element must have a fixed value of the same type, not ''{1}'' +SD_ELEMENT_PATTERN_NO_FIXED = The base element has a pattern type of ''{0}'', so this element must have a fixed value but it doesn''t SD_ELEMENT_REASON_DERIVED = , because the value must match the fixed value define in ''{0}'' SD_EXTENSION_URL_MISMATCH = The fixed value for the extension URL is {1} which doesn''t match the canonical URL {0} SD_EXTENSION_URL_MISSING = The value of Extension.url is not fixed to the extension URL {0} @@ -1152,7 +1153,7 @@ CODESYSTEM_CS_COMPLETE_AND_EMPTY = When a CodeSystem has content = ''complete'', VALIDATION_VAL_VERSION_NOHASH = Version ''{0}'' contains a ''#'', which as this character is used in some URLs to separate the version and the fragment id. When version does include '#', systems will not be able to parse the URL PRIMITIVE_TOO_SHORT = Value ''{0}'' is shorter than permitted minimum length of {1} CANONICAL_MULTIPLE_VERSIONS_KNOWN = The version {2} for the {0} {1} is not known. These versions are known: {3} -SD_PATH_SLICING_DEPRECATED = The discriminator type ''{0}'' has been deprecated. Use type=fixed with a pattern[x] instead +SD_PATH_SLICING_DEPRECATED = The discriminator type ''{0}'' has been deprecated. Use type=value with a pattern[x] instead SD_PATH_NOT_VALID = The discriminator path ''{0}'' does not appear to be valid for the element that is being sliced ''{1}'' SD_PATH_ERROR = The discriminator path ''{0}'' does not appear to be valid for the element that is being sliced ''{1}'': {2} diff --git a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/http/ManagedWebAccessAuthTests.java b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/http/ManagedWebAccessAuthTests.java index f57d93988..ced8783b2 100644 --- a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/http/ManagedWebAccessAuthTests.java +++ b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/http/ManagedWebAccessAuthTests.java @@ -164,7 +164,7 @@ public class ManagedWebAccessAuthTests { return new ServerDetailsPOJO( server.url("").toString(), "basic", - "dummyServerType", + "fhir", DUMMY_USERNAME, DUMMY_PASSWORD, null, null); @@ -183,7 +183,7 @@ public void testTokenAuthFromSettings() throws IOException, InterruptedException return new ServerDetailsPOJO( server.url("").toString(), "token", - "dummyServerType", + "fhir", null, null, DUMMY_TOKEN, null); @@ -202,7 +202,7 @@ public void testTokenAuthFromSettings() throws IOException, InterruptedException return new ServerDetailsPOJO( server.url("").toString(), "apikey", - "dummyServerType", + "fhir", null, null, null, DUMMY_API_KEY); 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 index 141ea3433..b8bf240f0 100644 --- 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 @@ -85,19 +85,19 @@ public class FhirSettingsTests implements ResourceLoaderTests { assertEquals("dummy-temp-path", fhirSettings.getTempPath()); assertEquals("dummy-test-igs-path", fhirSettings.getTestIgsPath()); - assertTrue(fhirSettings.getPackageManagement().getIgnoreDefaultServers()); + assertTrue(fhirSettings.getIgnoreDefaultPackageServers()); - List packageServers = fhirSettings.getPackageManagement().getServers(); + List servers = fhirSettings.getServers(); - assertEquals(2, packageServers.size()); + assertEquals(2, servers.size()); - assertEquals("http://dummy.org", packageServers.get(0).url); - assertEquals("npm", packageServers.get(0).serverType); - assertEquals("joe", packageServers.get(0).username); - assertEquals("swordfish", packageServers.get(0).password); - assertEquals("BASIC", packageServers.get(0).authenticationType); + assertEquals("http://dummy.org", servers.get(0).url); + assertEquals("npm-package", servers.get(0).type); + assertEquals("joe", servers.get(0).username); + assertEquals("swordfish", servers.get(0).password); + assertEquals("BASIC", servers.get(0).authenticationType); - assertEquals("http://dummy2.com", packageServers.get(1).url); + assertEquals("http://dummy2.com", servers.get(1).url); } } 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 index df0926920..9cd1f9aae 100644 --- a/org.hl7.fhir.utilities/src/test/resources/settings/settings-example.json +++ b/org.hl7.fhir.utilities/src/test/resources/settings/settings-example.json @@ -2,30 +2,28 @@ "apiKeys": { "dummy-api-key": "dummy-api-key-value" }, - "npmPath": "dummy-npm-path", + "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", - "packageManagement" : { - "ignoreDefaultServers" : true, - "servers": [ - { - "url": "http://dummy.org", - "serverType": "npm", - "authenticationType": "BASIC", - "username": "joe", - "password": "swordfish" - }, - { - "url": "http://dummy2.com", - "goobledy-goo": 5 - } - ] - }, - "unusedData" : { - "unusedDateField" : "unused-data" + "unusedField": "unused", + "ignoreDefaultPackageServers": true, + "servers": [ + { + "url": "http://dummy.org", + "type": "npm-package", + "authenticationType": "BASIC", + "username": "joe", + "password": "swordfish" + }, + { + "url": "http://dummy2.com", + "goobledy-goo": 5 + } + ], + "unusedData": { + "unusedDateField": "unused-data" } } \ No newline at end of file diff --git a/org.hl7.fhir.validation.cli/pom.xml b/org.hl7.fhir.validation.cli/pom.xml index f2f2abe5d..44944b33a 100644 --- a/org.hl7.fhir.validation.cli/pom.xml +++ b/org.hl7.fhir.validation.cli/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 6.4.1-SNAPSHOT + 6.4.2-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.validation/pom.xml b/org.hl7.fhir.validation/pom.xml index 208508c25..a70791f82 100644 --- a/org.hl7.fhir.validation/pom.xml +++ b/org.hl7.fhir.validation/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 6.4.1-SNAPSHOT + 6.4.2-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/IgLoader.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/IgLoader.java index 22c05b678..0c21b2822 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/IgLoader.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/IgLoader.java @@ -430,7 +430,7 @@ public class IgLoader implements IValidationEngineLoader { private InputStream fetchFromUrlSpecific(String source, boolean optional) throws FHIRException, IOException { try { - HTTPResult res = ManagedWebAccess.get(source + "?nocache=" + System.currentTimeMillis()); + HTTPResult res = ManagedWebAccess.get(Arrays.asList("web"), source + "?nocache=" + System.currentTimeMillis()); res.checkThrowException(); return new ByteArrayInputStream(res.getContent()); } catch (IOException e) { @@ -583,12 +583,12 @@ public class IgLoader implements IValidationEngineLoader { private byte[] fetchFromUrlSpecific(String source, String contentType, boolean optional, List errors) throws FHIRException, IOException { try { try { - // try with cache-busting option and then try withhout in case the server doesn't support that - HTTPResult res = ManagedWebAccess.get(source + "?nocache=" + System.currentTimeMillis(), contentType); + // try with cache-busting option and then try without in case the server doesn't support that + HTTPResult res = ManagedWebAccess.get(Arrays.asList("web"),source + "?nocache=" + System.currentTimeMillis(), contentType); res.checkThrowException(); return res.getContent(); } catch (Exception e) { - HTTPResult res = ManagedWebAccess.get(source, contentType); + HTTPResult res = ManagedWebAccess.get(Arrays.asList("web"), source, contentType); res.checkThrowException(); return res.getContent(); } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Scanner.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Scanner.java index d62bd106c..a0cb339a1 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Scanner.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Scanner.java @@ -8,13 +8,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -319,7 +313,7 @@ public class Scanner { } protected void download(String address, String filename) throws IOException { - HTTPResult res = ManagedWebAccess.get(address); + HTTPResult res = ManagedWebAccess.get(Arrays.asList("web"), address); res.checkThrowException(); TextFile.bytesToFile(res.getContent(), filename); } 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 863e02715..bc642efb3 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 @@ -19,7 +19,6 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; -import java.util.UUID; import org.fhir.ucum.UcumEssenceService; import org.hl7.fhir.convertors.factory.VersionConvertorFactory_10_50; @@ -72,12 +71,9 @@ import org.hl7.fhir.r5.utils.validation.IMessagingServices; import org.hl7.fhir.r5.utils.validation.IResourceValidator; import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor; import org.hl7.fhir.r5.utils.validation.IValidatorResourceFetcher; -import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor.AdditionalBindingPurpose; -import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor.CodedContentValidationAction; import org.hl7.fhir.r5.utils.validation.constants.BestPracticeWarningLevel; import org.hl7.fhir.r5.utils.validation.constants.BindingKind; import org.hl7.fhir.r5.utils.validation.constants.CheckDisplayOption; -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; @@ -942,7 +938,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP if (output.startsWith("http://")) { ByteArrayOutputStream bs = new ByteArrayOutputStream(); handleOutputToStream(r, output, bs, version); - HTTPResult res = ManagedWebAccess.post(output, bs.toByteArray(), "application/fhir+xml", "application/fhir+xml"); + HTTPResult res = ManagedWebAccess.post(Arrays.asList("web"), output, bs.toByteArray(), "application/fhir+xml", "application/fhir+xml"); res.checkThrowException(); } else { FileOutputStream s = ManagedFileAccess.outStream(output); @@ -1099,7 +1095,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP @Override public byte[] fetchRaw(IResourceValidator validator, String source) throws IOException { - HTTPResult res = ManagedWebAccess.get(source); + HTTPResult res = ManagedWebAccess.get(Arrays.asList("web"), source); res.checkThrowException(); return res.getContent(); } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/ProfileLoader.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/ProfileLoader.java index b73684eb6..6a41e1408 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/ProfileLoader.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/ProfileLoader.java @@ -2,6 +2,7 @@ package org.hl7.fhir.validation.cli.utils; import java.io.File; import java.io.IOException; +import java.util.Arrays; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.utilities.TextFile; @@ -25,7 +26,7 @@ public class ProfileLoader { private static byte[] loadProfileFromUrl(String src) throws FHIRException { try { - HTTPResult res = ManagedWebAccess.get(src + "?nocache=" + System.currentTimeMillis()); + HTTPResult res = ManagedWebAccess.get(Arrays.asList("web"), src + "?nocache=" + System.currentTimeMillis()); res.checkThrowException(); return res.getContent(); } catch (Exception e) { diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java index c598bae08..e8d0912d7 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java @@ -6368,7 +6368,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } // get the list of direct defined children, including slices - SourcedChildDefinitions childDefinitions = profileUtilities.getChildMap(profile, definition); + SourcedChildDefinitions childDefinitions = profileUtilities.getChildMap(profile, definition, false); if (childDefinitions.getList().isEmpty()) { if (actualType == null) { vi.setValid(false); @@ -6457,7 +6457,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat throw new DefinitionException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_ACTUAL_TYPE_, actualType)); trackUsage(dt, valContext, element); - childDefinitions = profileUtilities.getChildMap(dt, dt.getSnapshot().getElement().get(0)); + childDefinitions = profileUtilities.getChildMap(dt, dt.getSnapshot().getElement().get(0), false); return childDefinitions; } @@ -6998,7 +6998,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (ed.hasFixedCoding() && "http://loinc.org".equals(ed.getFixedCoding().getSystem())) { return ed.getFixedCoding().getCode(); } - SourcedChildDefinitions children = profileUtilities.getChildMap(profile, ed); + SourcedChildDefinitions children = profileUtilities.getChildMap(profile, ed, true); if (children != null) { for (ElementDefinition t : children.getList()) { if (t.getPath().endsWith(".code") && t.hasFixed()) { diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureDefinitionValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureDefinitionValidator.java index 1acff417c..235a448a8 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureDefinitionValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureDefinitionValidator.java @@ -503,9 +503,13 @@ public class StructureDefinitionValidator extends BaseValidator { } else { Element pattern = element.getNamedChild("pattern"); if (pattern != null) { - NodeStack fn = stack.push(pattern, 0, null, null); - if (rule(errors, "2024-03-26", IssueType.INVALID, fn, pattern.fhirType().equals(ed.getFixed().fhirType()), I18nConstants.SD_ELEMENT_PATTERN_WRONG_TYPE, pattern.fhirType(), ed.getFixed().fhirType())) { - ok = ((org.hl7.fhir.validation.instance.InstanceValidator) parent).checkFixedValue(errors, path, pattern, ed.getFixed(), base.getVersionedUrl(), "pattern", element, true, context.formatMessage(I18nConstants.SD_ELEMENT_REASON_DERIVED, base.getVersionedUrl())) && ok; + NodeStack fn = stack.push(pattern, 0, null, null); + if (rule(errors, "2024-03-26", IssueType.INVALID, fn, ed.hasFixed(), I18nConstants.SD_ELEMENT_PATTERN_NO_FIXED, pattern.fhirType())) { + if (rule(errors, "2024-03-26", IssueType.INVALID, fn, pattern.fhirType().equals(ed.getFixed().fhirType()), I18nConstants.SD_ELEMENT_PATTERN_WRONG_TYPE, pattern.fhirType(), ed.getFixed().fhirType())) { + ok = ((org.hl7.fhir.validation.instance.InstanceValidator) parent).checkFixedValue(errors, path, pattern, ed.getFixed(), base.getVersionedUrl(), "pattern", element, true, context.formatMessage(I18nConstants.SD_ELEMENT_REASON_DERIVED, base.getVersionedUrl())) && ok; + } else { + ok = false; + } } else { ok = false; } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ipa/IPAValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ipa/IPAValidator.java index 327567cc0..0cc39a5a6 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ipa/IPAValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ipa/IPAValidator.java @@ -2,6 +2,7 @@ package org.hl7.fhir.validation.ipa; import java.io.ByteArrayInputStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; @@ -160,7 +161,7 @@ public class IPAValidator { private Element makeRequest(ValidationNode vn, String url) { try { - HTTPResult result = ManagedWebAccess.get(url, "application/fhir+json"); + HTTPResult result = ManagedWebAccess.get(Arrays.asList("web"), url, "application/fhir+json"); if (result.getCode() >= 300) { vn.getIssues().add(new ValidationMessage(Source.IPAValidator, IssueType.EXCEPTION, "http.request", "HTTP Return code is "+result.getCode()+" "+result.getMessage(), diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxServiceTestHelper.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxServiceTestHelper.java index b9ea0ffdb..576b2aa50 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxServiceTestHelper.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxServiceTestHelper.java @@ -108,7 +108,7 @@ public class TxServiceTestHelper { writeDiffToFileSystem( name, expectedResponse, actualResponse); - String diff = CompareUtilities.checkJsonSrcIsSame(id, expectedResponse, actualResponse, externals); + String diff = new CompareUtilities(externals).checkJsonSrcIsSame(id, expectedResponse, actualResponse); if (diff != null) { Utilities.createDirectory(Utilities.getDirectoryForFile(fp)); TextFile.stringToFile(actualResponse, fp); @@ -182,7 +182,7 @@ public class TxServiceTestHelper { writeDiffToFileSystem(name, expectedResponse, actualResponse); - String diff = CompareUtilities.checkJsonSrcIsSame(id, expectedResponse, actualResponse, externals); + String diff = new CompareUtilities(externals).checkJsonSrcIsSame(id, expectedResponse, actualResponse); if (diff != null) { Utilities.createDirectory(Utilities.getDirectoryForFile(fp)); TextFile.stringToFile(actualResponse, fp); diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxTester.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxTester.java index 896fb2d75..e24462e2c 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxTester.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxTester.java @@ -19,8 +19,10 @@ import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.GregorianCalendar; +import java.util.HashMap; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.TimeZone; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -30,11 +32,13 @@ import org.hl7.fhir.convertors.txClient.TerminologyClientFactory; import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRFormatError; +import org.hl7.fhir.r4b.context.TextClientLogger; import org.hl7.fhir.r5.formats.IParser.OutputStyle; import org.hl7.fhir.r5.model.CapabilityStatement; import org.hl7.fhir.r5.model.OperationOutcome; import org.hl7.fhir.r5.model.Parameters; import org.hl7.fhir.r5.model.Resource; +import org.hl7.fhir.r5.model.TerminologyCapabilities; import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.terminologies.client.ITerminologyClient; import org.hl7.fhir.r5.test.utils.CompareUtilities; @@ -65,6 +69,8 @@ public class TxTester { private JsonObject externals; private String software; private List fails = new ArrayList<>(); + private CapabilityStatement cstmt; + private TerminologyCapabilities tc; public TxTester(ITxTesterLoader loader, String server, boolean tight, JsonObject externals) { @@ -107,14 +113,14 @@ public class TxTester { json.add("date", new SimpleDateFormat("EEE, MMM d, yyyy HH:mmZ", new Locale("en", "US")).format(Calendar.getInstance().getTime()) + timezone()); try { JsonObject tests = loadTests(); - ITerminologyClient tx = connectToServer(modes); - boolean ok = checkClient(tx); + tx = connectToServer(modes); + boolean ok = checkClient(); for (JsonObject suite : tests.getJsonObjects("suites")) { if ((!suite.has("mode") || modes.contains(suite.asString("mode")))) { if (suite.asBoolean("disabled")) { // ok = true; } else { - ok = runSuite(suite, tx, modes, filter, json.forceArray("suites")) && ok; + ok = runSuite(suite, modes, filter, json.forceArray("suites")) && ok; } } } @@ -123,10 +129,10 @@ public class TxTester { if (filter == null) { String m = modes.isEmpty() ? "[none]" : CommaSeparatedStringBuilder.join(";", modes); if (ok) { - System.out.println(software+" passed all HL7 terminology service tests (modes "+m+", tests v"+loadVersion()+", runner v"+VersionUtil.getBaseVersion()+")"); + System.out.println(software+" passed all HL7 terminology service tests ("+Utilities.pluralize("mode", modes.size())+" "+m+", tests v"+loadVersion()+", runner v"+VersionUtil.getBaseVersion()+")"); return true; } else { - System.out.println(software+" did not pass all HL7 terminology service tests (modes "+m+", tests v"+loadVersion()+", runner v"+VersionUtil.getBaseVersion()+")"); + System.out.println(software+" did not pass all HL7 terminology service tests ("+Utilities.pluralize("mode", modes.size())+" "+m+", tests v"+loadVersion()+", runner v"+VersionUtil.getBaseVersion()+")"); System.out.println("Failed Tests: "+ CommaSeparatedStringBuilder.join(",", fails )); return false; } @@ -153,12 +159,12 @@ public class TxTester { return offset; } - private boolean checkClient(ITerminologyClient tx) { - CapabilityStatement cstmt = tx.getCapabilitiesStatementQuick(); + private boolean checkClient() { + cstmt = tx.getCapabilitiesStatement(); if (cstmt.hasSoftware()) { software = cstmt.getSoftware().getName()+" v"+cstmt.getSoftware().getVersion(); } - tx.getTerminologyCapabilities(); + tc = tx.getTerminologyCapabilities(); return true; } @@ -171,7 +177,7 @@ public class TxTester { return processHistoryMarkdown(loader.loadContent("history.md")); } - private String processHistoryMarkdown(byte[] content) throws IOException { + public static String processHistoryMarkdown(byte[] content) throws IOException { DataInputStream in = new DataInputStream(new ByteArrayInputStream(content)); BufferedReader br = new BufferedReader(new InputStreamReader(in)); try { @@ -179,7 +185,7 @@ public class TxTester { //Read File Line By Line while ((strLine = br.readLine()) != null) { if (strLine.startsWith("## ")) { - return strLine.substring(3); + return strLine.substring(3).trim(); } } } finally { @@ -189,7 +195,7 @@ public class TxTester { return "<1.6.0"; } - private ITerminologyClient connectToServer(List modes) throws URISyntaxException { + private ITerminologyClient connectToServer(List modes) throws URISyntaxException, IOException { System.out.println("Connect to "+server); software = server; ITerminologyClient client = new TerminologyClientFactory(FhirPublication.R4).makeClient("Test-Server", server, "Tools/Java", null); @@ -201,18 +207,18 @@ public class TxTester { error = null; if (tx == null) { tx = connectToServer(modes); - checkClient(tx); + checkClient(); } List setup = loadSetupResources(suite); - if (runTest(suite, test, tx, setup, modes, "*", null)) { + if (runTest(suite, test, setup, modes, "*", null)) { return null; } else { return error; } } - private boolean runSuite(JsonObject suite, ITerminologyClient tx, List modes, String filter, JsonArray output) throws FHIRFormatError, FileNotFoundException, IOException { + private boolean runSuite(JsonObject suite, List modes, String filter, JsonArray output) throws FHIRFormatError, FileNotFoundException, IOException { System.out.println("Group "+suite.asString("name")); JsonObject outputS = new JsonObject(); if (output != null) { @@ -226,14 +232,14 @@ public class TxTester { if (test.asBoolean("disabled")) { ok = true; } else { - ok = runTest(suite, test, tx, setup, modes, filter, outputS.forceArray("tests")) && ok; + ok = runTest(suite, test, setup, modes, filter, outputS.forceArray("tests")) && ok; } } } return ok; } - private boolean runTest(JsonObject suite, JsonObject test, ITerminologyClient tx, List setup, List modes, String filter, JsonArray output) throws FHIRFormatError, DefinitionException, FileNotFoundException, FHIRException, IOException { + private boolean runTest(JsonObject suite, JsonObject test, List setup, List modes, String filter, JsonArray output) throws FHIRFormatError, DefinitionException, FileNotFoundException, FHIRException, IOException { JsonObject outputT = new JsonObject(); if (output != null) { output.add(outputT); @@ -253,7 +259,8 @@ public class TxTester { } } - Parameters req = (Parameters) loader.loadResource(chooseParam(test, "request", modes)); + String reqFile = chooseParam(test, "request", modes); + Parameters req = reqFile == null ? null : (Parameters) loader.loadResource(reqFile); String fn = chooseParam(test, "response", modes); String resp = TextFile.bytesToString(loader.loadContent(fn)); @@ -266,16 +273,20 @@ public class TxTester { String lang = test.asString("Content-Language"); String msg = null; - if (test.asString("operation").equals("expand")) { - msg = expand(test.str("name"), tx, setup, req, resp, fp, lang, profile, ext, getResponseCode(test)); + if (test.asString("operation").equals("metadata")) { + msg = metadata(test.str("name"), setup, resp, fp, lang, profile, ext); + } else if (test.asString("operation").equals("term-caps")) { + msg = termcaps(test.str("name"), setup, resp, fp, lang, profile, ext); + } else if (test.asString("operation").equals("expand")) { + msg = expand(test.str("name"), setup, req, resp, fp, lang, profile, ext, getResponseCode(test)); } else if (test.asString("operation").equals("validate-code")) { - msg = validate(test.str("name"),tx, setup, req, resp, fp, lang, profile, ext, getResponseCode(test)); + msg = validate(test.str("name"), setup, req, resp, fp, lang, profile, ext, getResponseCode(test)); } else if (test.asString("operation").equals("cs-validate-code")) { - msg = validateCS(test.str("name"),tx, setup, req, resp, fp, lang, profile, ext, getResponseCode(test)); + msg = validateCS(test.str("name"), setup, req, resp, fp, lang, profile, ext, getResponseCode(test)); } else if (test.asString("operation").equals("lookup")) { - msg = lookup(test.str("name"),tx, setup, req, resp, fp, lang, profile, ext, getResponseCode(test)); + msg = lookup(test.str("name"), setup, req, resp, fp, lang, profile, ext, getResponseCode(test)); } else if (test.asString("operation").equals("translate")) { - msg = translate(test.str("name"),tx, setup, req, resp, fp, lang, profile, ext, getResponseCode(test)); + msg = translate(test.str("name"), setup, req, resp, fp, lang, profile, ext, getResponseCode(test)); } else { throw new Exception("Unknown Operation "+test.asString("operation")); } @@ -311,6 +322,34 @@ public class TxTester { } } + private String metadata(String id, List setup, String resp, String fp, String lang, Parameters profile, JsonObject ext) throws IOException { + CapabilityStatement cs = cstmt.copy(); + TxTesterScrubbers.scrubCapStmt(cs, tight); + TxTesterSorters.sortCapStmt(cs); + String csj = new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).composeString(cs); + + String diff = new CompareUtilities(ext, vars()).setPatternMode(true).checkJsonSrcIsSame(id, resp, csj, false); + if (diff != null) { + Utilities.createDirectory(Utilities.getDirectoryForFile(fp)); + TextFile.stringToFile(csj, fp); + } + return diff; + } + + private String termcaps(String id, List setup, String resp, String fp, String lang, Parameters profile, JsonObject ext) throws IOException { + TerminologyCapabilities cs = tc.copy(); + TxTesterScrubbers.scrubTermCaps(cs, tight); + TxTesterSorters.sortTermCaps(cs); + String csj = new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).composeString(cs); + + String diff = new CompareUtilities(ext, vars()).setPatternMode(true).checkJsonSrcIsSame(id, resp, csj, false); + if (diff != null) { + Utilities.createDirectory(Utilities.getDirectoryForFile(fp)); + TextFile.stringToFile(csj, fp); + } + return diff; + } + private String getResponseCode(JsonObject test) { if (test.has("http-code")) { return test.asString("http-code"); @@ -340,7 +379,7 @@ public class TxTester { return new URI(server).getHost(); } - private String lookup(String id, ITerminologyClient tx, List setup, Parameters p, String resp, String fp, String lang, Parameters profile, JsonObject ext, String tcode) throws IOException { + private String lookup(String id, List setup, Parameters p, String resp, String fp, String lang, Parameters profile, JsonObject ext, String tcode) throws IOException { for (Resource r : setup) { p.addParameter().setName("tx-resource").setResource(r); } @@ -363,7 +402,7 @@ public class TxTester { if (tcode != null && !httpCodeOk(tcode, code)) { return "Response Code fail: should be '"+tcode+"' but is '"+code+"'"; } - String diff = CompareUtilities.checkJsonSrcIsSame(id, resp, pj, false, ext); + String diff = new CompareUtilities(ext, vars()).checkJsonSrcIsSame(id, resp, pj, false); if (diff != null) { Utilities.createDirectory(Utilities.getDirectoryForFile(fp)); TextFile.stringToFile(pj, fp); @@ -371,7 +410,7 @@ public class TxTester { return diff; } - private String translate(String id, ITerminologyClient tx, List setup, Parameters p, String resp, String fp, String lang, Parameters profile, JsonObject ext, String tcode) throws IOException { + private String translate(String id, List setup, Parameters p, String resp, String fp, String lang, Parameters profile, JsonObject ext, String tcode) throws IOException { for (Resource r : setup) { p.addParameter().setName("tx-resource").setResource(r); } @@ -394,7 +433,7 @@ public class TxTester { if (tcode != null && !httpCodeOk(tcode, code)) { return "Response Code fail: should be '"+tcode+"' but is '"+code+"'"; } - String diff = CompareUtilities.checkJsonSrcIsSame(id, resp, pj, false, ext); + String diff = new CompareUtilities(ext, vars()).checkJsonSrcIsSame(id, resp, pj, false); if (diff != null) { Utilities.createDirectory(Utilities.getDirectoryForFile(fp)); TextFile.stringToFile(pj, fp); @@ -402,7 +441,7 @@ public class TxTester { return diff; } - private String expand(String id, ITerminologyClient tx, List setup, Parameters p, String resp, String fp, String lang, Parameters profile, JsonObject ext, String tcode) throws IOException { + private String expand(String id, List setup, Parameters p, String resp, String fp, String lang, Parameters profile, JsonObject ext, String tcode) throws IOException { for (Resource r : setup) { p.addParameter().setName("tx-resource").setResource(r); } @@ -425,7 +464,7 @@ public class TxTester { if (tcode != null && !httpCodeOk(tcode, code)) { return "Response Code fail: should be '"+tcode+"' but is '"+code+"'"; } - String diff = CompareUtilities.checkJsonSrcIsSame(id, resp, vsj, false, ext); + String diff = new CompareUtilities(ext, vars()).checkJsonSrcIsSame(id, resp, vsj, false); if (diff != null) { Utilities.createDirectory(Utilities.getDirectoryForFile(fp)); TextFile.stringToFile(vsj, fp); @@ -444,7 +483,7 @@ public class TxTester { } } - private String validate(String id, ITerminologyClient tx, List setup, Parameters p, String resp, String fp, String lang, Parameters profile, JsonObject ext, String tcode) throws IOException { + private String validate(String id, List setup, Parameters p, String resp, String fp, String lang, Parameters profile, JsonObject ext, String tcode) throws IOException { for (Resource r : setup) { p.addParameter().setName("tx-resource").setResource(r); } @@ -468,7 +507,7 @@ public class TxTester { if (tcode != null && !httpCodeOk(tcode, code)) { return "Response Code fail: should be '"+tcode+"' but is '"+code+"'"; } - String diff = CompareUtilities.checkJsonSrcIsSame(id, resp, pj, false, ext); + String diff = new CompareUtilities(ext, vars()).checkJsonSrcIsSame(id, resp, pj, false); if (diff != null) { Utilities.createDirectory(Utilities.getDirectoryForFile(fp)); TextFile.stringToFile(pj, fp); @@ -476,7 +515,7 @@ public class TxTester { return diff; } - private String validateCS(String id, ITerminologyClient tx, List setup, Parameters p, String resp, String fp, String lang, Parameters profile, JsonObject ext, String tcode) throws IOException { + private String validateCS(String id, List setup, Parameters p, String resp, String fp, String lang, Parameters profile, JsonObject ext, String tcode) throws IOException { for (Resource r : setup) { p.addParameter().setName("tx-resource").setResource(r); } @@ -499,7 +538,7 @@ public class TxTester { if (tcode != null && !httpCodeOk(tcode, code)) { return "Response Code fail: should be '"+tcode+"' but is '"+code+"'"; } - String diff = CompareUtilities.checkJsonSrcIsSame(id, resp, pj, false, ext); + String diff = new CompareUtilities(ext, vars()).checkJsonSrcIsSame(id, resp, pj, false); if (diff != null) { Utilities.createDirectory(Utilities.getDirectoryForFile(fp)); TextFile.stringToFile(pj, fp); @@ -508,6 +547,13 @@ public class TxTester { } + private Map vars() { + Map vars = new HashMap(); + vars.put("version", tx.getActualVersion().toCode()); + return vars; + + } + private List loadSetupResources(JsonObject suite) throws FHIRFormatError, FileNotFoundException, IOException { List res = new ArrayList<>(); for (String s : suite.getStrings("setup")) { diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxTesterScrubbers.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxTesterScrubbers.java index 1a578c945..1e25d06c8 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxTesterScrubbers.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxTesterScrubbers.java @@ -1,5 +1,7 @@ package org.hl7.fhir.validation.special; +import org.hl7.fhir.r5.model.CapabilityStatement; +import org.hl7.fhir.r5.model.CapabilityStatement.CapabilityStatementRestComponent; import org.hl7.fhir.r5.model.DomainResource; import org.hl7.fhir.r5.model.Element; import org.hl7.fhir.r5.model.Extension; @@ -7,6 +9,7 @@ import org.hl7.fhir.r5.model.OperationOutcome; import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent; import org.hl7.fhir.r5.model.Parameters; import org.hl7.fhir.r5.model.Resource; +import org.hl7.fhir.r5.model.TerminologyCapabilities; import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.utils.ElementVisitor; import org.hl7.fhir.r5.utils.ElementVisitor.ElementVisitorInstruction; @@ -98,4 +101,12 @@ public class TxTesterScrubbers { } } + public static void scrubCapStmt(CapabilityStatement cs, boolean tight) { + // nothing yet? + } + + public static void scrubTermCaps(TerminologyCapabilities cs, boolean tight) { + // nothing yet? + } + } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxTesterSorters.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxTesterSorters.java index b93f05d8b..bc232417f 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxTesterSorters.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxTesterSorters.java @@ -8,18 +8,34 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; - import org.hl7.fhir.r5.formats.IParser.OutputStyle; import org.hl7.fhir.r5.formats.JsonParser; - +import org.hl7.fhir.r5.model.CanonicalType; +import org.hl7.fhir.r5.model.CapabilityStatement; import org.hl7.fhir.r5.model.Extension; import org.hl7.fhir.r5.model.OperationOutcome; import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent; import org.hl7.fhir.r5.model.Parameters; import org.hl7.fhir.r5.model.Parameters.ParametersParameterComponent; +import org.hl7.fhir.r5.model.TerminologyCapabilities.TerminologyCapabilitiesCodeSystemComponent; +import org.hl7.fhir.r5.model.TerminologyCapabilities.TerminologyCapabilitiesCodeSystemVersionComponent; +import org.hl7.fhir.r5.model.TerminologyCapabilities.TerminologyCapabilitiesCodeSystemVersionFilterComponent; +import org.hl7.fhir.r5.model.TerminologyCapabilities.TerminologyCapabilitiesExpansionParameterComponent; import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.StringType; +import org.hl7.fhir.r5.model.TerminologyCapabilities; import org.hl7.fhir.r5.model.ValueSet; +import org.hl7.fhir.r5.model.CapabilityStatement.CapabilityStatementRestComponent; +import org.hl7.fhir.r5.model.CapabilityStatement.CapabilityStatementRestResourceComponent; +import org.hl7.fhir.r5.model.CapabilityStatement.CapabilityStatementRestResourceOperationComponent; +import org.hl7.fhir.r5.model.CapabilityStatement.CapabilityStatementRestResourceSearchParamComponent; +import org.hl7.fhir.r5.model.CapabilityStatement.ResourceInteractionComponent; +import org.hl7.fhir.r5.model.CapabilityStatement.SystemInteractionComponent; +import org.hl7.fhir.r5.model.Enumerations.CommonLanguages; +import org.hl7.fhir.r5.model.CodeType; +import org.hl7.fhir.r5.model.CodeableConcept; +import org.hl7.fhir.r5.model.Coding; +import org.hl7.fhir.r5.model.Enumeration; import org.hl7.fhir.r5.model.ValueSet.ConceptPropertyComponent; import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceDesignationComponent; import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent; @@ -27,9 +43,11 @@ import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionParameterComponent; import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionPropertyComponent; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.json.JsonException; +import org.hl7.fhir.validation.special.TxTesterSorters.CodeTypeSorter; public class TxTesterSorters { + public static void main(String[] args) throws JsonException, IOException { Resource r = new JsonParser().parse(new FileInputStream(args[0])); switch (r.fhirType()) { @@ -234,7 +252,205 @@ public class TxTesterSorters { } } + + public static void sortCapStmt(CapabilityStatement cs) { + Collections.sort(cs.getFormat(), new CodeTypeSorter()); + Collections.sort(cs.getInstantiates(), new CanonicalTypeSorter()); + Collections.sort(cs.getImports(), new CanonicalTypeSorter()); + Collections.sort(cs.getAcceptLanguage(), new CodeTypeSorter()); + Collections.sort(cs.getRest(), new CSRestSorter()); + for (CapabilityStatementRestComponent r : cs.getRest()) { + if (r.hasSecurity()) { + for (CodeableConcept cc : r.getSecurity().getService()) { + Collections.sort(cc.getCoding(), new CodingSorter()); + } + Collections.sort(r.getSecurity().getService(), new CodeableConceptSorter()); + } + Collections.sort(r.getResource(), new CSRestResourceSorter()); + for (CapabilityStatementRestResourceComponent res : r.getResource()) { + Collections.sort(res.getSupportedProfile(), new CanonicalTypeSorter()); + Collections.sort(res.getInteraction(), new CSRestResourceInteractionSorter()); + Collections.sort(res.getSearchInclude(), new StringTypeSorter()); + Collections.sort(res.getSearchRevInclude(), new StringTypeSorter()); + Collections.sort(res.getSearchParam(), new SearchParamSorter()); + Collections.sort(res.getOperation(), new CSRestResourceOperationSorter()); + } + Collections.sort(r.getInteraction(), new CSRestInteractionSorter()); + Collections.sort(r.getSearchParam(), new SearchParamSorter()); + Collections.sort(r.getOperation(), new CSRestResourceOperationSorter()); + Collections.sort(r.getCompartment(), new CanonicalTypeSorter()); + } + } + + public static class CodeTypeSorter implements Comparator { + + @Override + public int compare(CodeType o1, CodeType o2) { + return o1.asStringValue().compareTo(o2.asStringValue()); + } + + } + + public static class StringTypeSorter implements Comparator { + + @Override + public int compare(StringType o1, StringType o2) { + return o1.asStringValue().compareTo(o2.asStringValue()); + } + + } + + public static class CanonicalTypeSorter implements Comparator { + + @Override + public int compare(CanonicalType o1, CanonicalType o2) { + return o1.asStringValue().compareTo(o2.asStringValue()); + } + + } + + public static class CodingSorter implements Comparator { + + @Override + public int compare(Coding c1, Coding c2) { + if (c1.getSystem().equals(c2.getSystem())) { + return c1.getCode().compareTo(c2.getCode()); + } else { + return c1.getSystem().compareTo(c2.getSystem()); + } + } + + } + public static class CodeableConceptSorter implements Comparator { + + @Override + public int compare(CodeableConcept o1, CodeableConcept o2) { + if (o1.hasCoding() && o2.hasCoding()) { + Coding c1 = o1.getCodingFirstRep(); + Coding c2 = o2.getCodingFirstRep(); + if (c1.getSystem().equals(c2.getSystem())) { + return c1.getCode().compareTo(c2.getCode()); + } else { + return c1.getSystem().compareTo(c2.getSystem()); + } + } else { + return o1.getText().compareTo(o2.getText()); + } + } + + } + + public static class CSRestSorter implements Comparator { + + @Override + public int compare(CapabilityStatementRestComponent o1, CapabilityStatementRestComponent o2) { + return o1.getMode().compareTo(o2.getMode()); + } + + } + + public static class CSRestResourceSorter implements Comparator { + + @Override + public int compare(CapabilityStatementRestResourceComponent o1, CapabilityStatementRestResourceComponent o2) { + return o1.getType().compareTo(o2.getType()); + } + + } + + public static class CSRestResourceInteractionSorter implements Comparator { + + @Override + public int compare(ResourceInteractionComponent o1, ResourceInteractionComponent o2) { + return o1.getCode().toCode().compareTo(o2.getCode().toCode()); + } + + } + + public static class CSRestInteractionSorter implements Comparator { + + @Override + public int compare(SystemInteractionComponent o1, SystemInteractionComponent o2) { + return o1.getCode().compareTo(o2.getCode()); + } + + } - + public static class SearchParamSorter implements Comparator { + + @Override + public int compare(CapabilityStatementRestResourceSearchParamComponent o1, CapabilityStatementRestResourceSearchParamComponent o2) { + return o1.getName().compareTo(o2.getName()); + } + + } + + public static class CSRestResourceOperationSorter implements Comparator { + + @Override + public int compare(CapabilityStatementRestResourceOperationComponent o1, CapabilityStatementRestResourceOperationComponent o2) { + return o1.getName().compareTo(o2.getName()); + } + + } + + public static void sortTermCaps(TerminologyCapabilities tc) { + Collections.sort(tc.getCodeSystem(), new TCCodeSystemSorter()); + for (TerminologyCapabilitiesCodeSystemComponent t : tc.getCodeSystem()) { + Collections.sort(t.getVersion(), new TCCodeSystemVersionSorter()); + for (TerminologyCapabilitiesCodeSystemVersionComponent v : t.getVersion()) { + Collections.sort(v.getLanguage(), new LanguageSorter()); + Collections.sort(v.getProperty(), new CodeTypeSorter()); + Collections.sort(v.getFilter(), new TCCodeSystemVersionFilterSorter()); + } + } + Collections.sort(tc.getExpansion().getParameter(), new TCExpansionParameterSorter()); + } + + + public static class LanguageSorter implements Comparator> { + + @Override + public int compare(Enumeration o1, Enumeration o2) { + return o1.asStringValue().compareTo(o2.asStringValue()); + } + + } + public static class TCCodeSystemSorter implements Comparator { + + @Override + public int compare(TerminologyCapabilitiesCodeSystemComponent o1, TerminologyCapabilitiesCodeSystemComponent o2) { + return o1.getUri().compareTo(o2.getUri()); + } + + } + + public static class TCCodeSystemVersionSorter implements Comparator { + + @Override + public int compare(TerminologyCapabilitiesCodeSystemVersionComponent o1, TerminologyCapabilitiesCodeSystemVersionComponent o2) { + return o1.getCode() == null || o2.getCode() == null ? 0 : o1.getCode().compareTo(o2.getCode()); + } + + } + + public static class TCCodeSystemVersionFilterSorter implements Comparator { + + @Override + public int compare(TerminologyCapabilitiesCodeSystemVersionFilterComponent o1, TerminologyCapabilitiesCodeSystemVersionFilterComponent o2) { + return o1.getCode().compareTo(o2.getCode()); + } + } + + public static class TCExpansionParameterSorter implements Comparator { + + @Override + public int compare(TerminologyCapabilitiesExpansionParameterComponent o1, TerminologyCapabilitiesExpansionParameterComponent o2) { + return o1.getName().compareTo(o2.getName()); + } + + } + + } diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/comparison/tests/ComparisonTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/comparison/tests/ComparisonTests.java index 9f1a7bb7c..c3c662c92 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/comparison/tests/ComparisonTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/comparison/tests/ComparisonTests.java @@ -245,7 +245,7 @@ public class ComparisonTests { String en = Utilities.path("[tmp]", "comparison", Utilities.changeFileExt(name, ".expected.html")); TextFile.stringToFile(expected, en); - String msg = CompareUtilities.checkXMLIsSame(id, en, an); + String msg = new CompareUtilities().checkXMLIsSame(id, en, an); Assertions.assertTrue(msg == null, "Output does not match expected: "+msg); } diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/terminology/tests/LocalTerminologyServiceTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/terminology/tests/LocalTerminologyServiceTests.java index fb175b81f..27bfaf9ef 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/terminology/tests/LocalTerminologyServiceTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/terminology/tests/LocalTerminologyServiceTests.java @@ -20,7 +20,9 @@ import org.hl7.fhir.r5.model.Constants; import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.test.utils.TestingUtilities; import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.utilities.VersionUtil; import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; +import org.hl7.fhir.utilities.json.JsonException; import org.hl7.fhir.utilities.json.model.JsonObject; import org.hl7.fhir.utilities.settings.FhirSettings; import org.hl7.fhir.utilities.tests.TestConfig; @@ -81,6 +83,7 @@ public class LocalTerminologyServiceTests implements ITxTesterLoader { for (String id : names) { objects.add(new Object[]{id, examples.get(id)}); } + objects.add(new Object[]{"final", null}); return objects; } @@ -90,6 +93,7 @@ public class LocalTerminologyServiceTests implements ITxTesterLoader { private String version = "5.0.0"; private static TxTester tester; private List modes = new ArrayList<>(); + private boolean error = false; public LocalTerminologyServiceTests(String name, JsonObjectPair setup) { this.setup = setup; @@ -107,19 +111,33 @@ public class LocalTerminologyServiceTests implements ITxTesterLoader { logTestSkip("No local terminology server available."); return; } - if (SERVER != null) { - if (tester == null) { - tester = new TxTester(this, SERVER, true, externals); + if (setup == null) { + if (!error) { + System.out.println("tx.fhir.org passed all HL7 terminology service tests (mode 'tx.fhir.org', tests v"+loadVersion()+", runner v"+VersionUtil.getBaseVersion()+")"); } - String err = tester.executeTest(setup.suite, setup.test, modes); - Assertions.assertTrue(err == null, err); + Assertions.assertTrue(!error); } else { - Assertions.assertTrue(true); + if (SERVER != null) { + if (tester == null) { + tester = new TxTester(this, SERVER, true, externals); + } + String err = tester.executeTest(setup.suite, setup.test, modes); + error = error || err != null; + Assertions.assertTrue(err == null, err); + } else { + Assertions.assertTrue(true); + } } } + private String loadVersion() throws JsonException, IOException { + return TxTester.processHistoryMarkdown(TestingUtilities.loadTestResourceBytes("tx", "history.md")); + } + private void logTestSkip(String reason) { - System.out.println("Skipping test: " + setup.suite.asString("name") + " " + setup.test.asString("name") + " reason: " + reason); + if (setup != null) { + System.out.println("Skipping test: " + setup.suite.asString("name") + " " + setup.test.asString("name") + " reason: " + reason); + } } public Resource loadResource(String filename) throws IOException, FHIRFormatError, FileNotFoundException, FHIRException, DefinitionException { diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/terminology/tests/TerminologyServiceTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/terminology/tests/TerminologyServiceTests.java index f3a20c54f..a6e617e94 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/terminology/tests/TerminologyServiceTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/terminology/tests/TerminologyServiceTests.java @@ -92,7 +92,8 @@ private static TxTestData testData; if (setup.getSuite().asBoolean("disabled") || setup.getTest().asBoolean("disabled")) { return; } - Resource req = loadResource(setup.getTest().asString("request")); + String reqFile = setup.getTest().asString("request"); + Resource req = reqFile == null ? null : loadResource(reqFile); String fn = setup.getTest().has("response:tx.fhir.org") ? setup.getTest().asString("response:tx.fhir.org") : setup.getTest().asString("response"); String resp = TestingUtilities.loadTestResource("tx", fn); String fp = Utilities.path("[tmp]", "tx", fn); @@ -114,7 +115,7 @@ private static TxTestData testData; } else if (setup.getTest().asString("operation").equals("cs-validate-code")) { String diff = TxServiceTestHelper.getDiffForValidation(setup.getTest().str("name"), engine.getContext(), setup.getTest().asString("name"), req, resp, setup.getTest().asString("Content-Language"), fp, ext, true); assertNull(diff, diff); - } else if (Utilities.existsInList(setup.getTest().asString("operation"), "lookup", "translate")) { + } else if (Utilities.existsInList(setup.getTest().asString("operation"), "lookup", "translate", "metadata", "term-caps")) { Assertions.assertTrue(true); // we don't test these for the internal server } else { Assertions.fail("Unknown Operation "+ setup.getTest().asString("operation")); @@ -140,7 +141,7 @@ private static TxTestData testData; TxTesterSorters.sortValueSet(vse.getValueset()); TxTesterScrubbers.scrubVS(vse.getValueset(), false); String vsj = new JsonParser().setOutputStyle(OutputStyle.PRETTY).composeString(vse.getValueset()); - String diff = CompareUtilities.checkJsonSrcIsSame(id, resp, vsj, ext); + String diff = new CompareUtilities(ext).checkJsonSrcIsSame(id, resp, vsj); if (diff != null) { Utilities.createDirectory(Utilities.getDirectoryForFile(fp)); TextFile.stringToFile(vsj, fp); @@ -189,7 +190,7 @@ private static TxTestData testData; TxTesterScrubbers.scrubOO(oo, false); String ooj = new JsonParser().setOutputStyle(OutputStyle.PRETTY).composeString(oo); - String diff = CompareUtilities.checkJsonSrcIsSame(id, resp, ooj, ext); + String diff = new CompareUtilities(ext).checkJsonSrcIsSame(id, resp, ooj); if (diff != null) { Utilities.createDirectory(Utilities.getDirectoryForFile(fp)); TextFile.stringToFile(ooj, fp); diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/StructureMappingTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/StructureMappingTests.java index acc1c4b4b..c6268dfd6 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/StructureMappingTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/StructureMappingTests.java @@ -121,11 +121,11 @@ public class StructureMappingTests { fail(e.getMessage()); } if (output.endsWith("json")) { - msg = CompareUtilities.checkJsonSrcIsSame(name, s.toString(), outputJson, null); + msg = new CompareUtilities().checkJsonSrcIsSame(name, s.toString(), outputJson); } else { TextFile.bytesToFile(s.toByteArray(), fileOutputRes); TextFile.bytesToFile(outputJson.getBytes(), fileOutputResOrig); - msg = CompareUtilities.checkXMLIsSame(name, ManagedFileAccess.inStream(fileOutputResOrig), ManagedFileAccess.inStream(fileOutputRes)); + msg = new CompareUtilities().checkXMLIsSame(name, ManagedFileAccess.inStream(fileOutputResOrig), ManagedFileAccess.inStream(fileOutputRes)); } if (!Utilities.noString(msg)) { System.out.print(s.toString()); diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTests.java index e4b712a70..0ef47c537 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTests.java @@ -8,17 +8,8 @@ import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; -import java.util.Set; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.NotImplementedException; @@ -858,7 +849,7 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe @Override public byte[] fetchRaw(IResourceValidator validator, String source) throws MalformedURLException, IOException { - HTTPResult res = ManagedWebAccess.get(source); + HTTPResult res = ManagedWebAccess.get(Arrays.asList("web"), source); res.checkThrowException(); return res.getContent(); } diff --git a/pom.xml b/pom.xml index e408832b0..4a07fdbf3 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ HAPI FHIR --> org.hl7.fhir.core - 6.4.1-SNAPSHOT + 6.4.2-SNAPSHOT pom @@ -23,7 +23,7 @@ 2.17.0 32.0.1-jre 6.4.1 - 1.6.1-SNAPSHOT + 1.6.6-SNAPSHOT 2.17.0 5.9.2 1.8.2