This commit is contained in:
Lloyd McKenzie 2024-10-02 21:02:40 -06:00
commit ee7c2b9413
94 changed files with 23623 additions and 3552 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -2,4 +2,4 @@ Locale,Coverage #,Coverage %
de,831,40%
es,714,35%
ja,902,44%
nl,1989,98%
nl,1988,97%

1 Locale Coverage # Coverage %
2 de 831 40%
3 es 714 35%
4 ja 902 44%
5 nl 1989 1988 98% 97%

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.27-SNAPSHOT</version>
<version>6.3.30-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -25,8 +25,10 @@ import org.hl7.fhir.r4.model.StringType;
import org.hl7.fhir.r5.model.CodeType;
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingAdditionalComponent;
import org.hl7.fhir.r5.model.UsageContext;
import org.hl7.fhir.r5.utils.ToolingExtensions;
public class ElementDefinition40_50 {
public static org.hl7.fhir.r5.model.ElementDefinition convertElementDefinition(org.hl7.fhir.r4.model.ElementDefinition src) throws FHIRException {
if (src == null) return null;
org.hl7.fhir.r5.model.ElementDefinition tgt = new org.hl7.fhir.r5.model.ElementDefinition();
@ -616,7 +618,7 @@ public class ElementDefinition40_50 {
if (src == null) return null;
org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent tgt = new org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent();
ConversionContext40_50.INSTANCE.getVersionConvertor_40_50().copyElement(src, tgt,
"http://hl7.org/fhir/5.0/StructureDefinition/extension-ElementDefinition.binding.additional");
"http://hl7.org/fhir/5.0/StructureDefinition/extension-ElementDefinition.binding.additional", ToolingExtensions.EXT_BINDING_ADDITIONAL);
if (src.hasStrength()) tgt.setStrengthElement(Enumerations40_50.convertBindingStrength(src.getStrengthElement()));
if (src.hasDescription()) tgt.setDescriptionElement(String40_50.convertStringToMarkdown(src.getDescriptionElement()));
if (src.hasValueSet()) tgt.setValueSetElement(Canonical40_50.convertCanonical(src.getValueSetElement()));
@ -624,6 +626,9 @@ public class ElementDefinition40_50 {
for (org.hl7.fhir.r4.model.Extension ext : src.getExtensionsByUrl("http://hl7.org/fhir/5.0/StructureDefinition/extension-ElementDefinition.binding.additional")) {
tgt.addAdditional(convertAdditional(ext));
}
for (org.hl7.fhir.r4.model.Extension ext : src.getExtensionsByUrl(ToolingExtensions.EXT_BINDING_ADDITIONAL)) {
tgt.addAdditional(convertAdditional(ext));
}
return tgt;
}
@ -652,12 +657,12 @@ public class ElementDefinition40_50 {
return tgt;
}
private static Extension convertAdditional(ElementDefinitionBindingAdditionalComponent src) {
private static org.hl7.fhir.r4.model.Extension convertAdditional(ElementDefinitionBindingAdditionalComponent src) {
if (src == null) return null;
Extension tgt = new Extension();
org.hl7.fhir.r4.model.Extension tgt = new Extension(ToolingExtensions.EXT_BINDING_ADDITIONAL);
ConversionContext40_50.INSTANCE.getVersionConvertor_40_50().copyElement(src, tgt);
if (src.hasPurpose()) {
tgt.addExtension(new Extension("purpose", new CodeType(src.getPurposeElement().primitiveValue())));
tgt.addExtension(new Extension("purpose", new org.hl7.fhir.r4.model.CodeType(src.getPurposeElement().primitiveValue())));
}
if (src.hasValueSet()) {
tgt.addExtension(new Extension("valueSet", Canonical40_50.convertCanonical(src.getValueSetElement())));

View File

@ -230,12 +230,6 @@ public class Enumerations40_50 {
case _4_3_0:
tgt.setValue(org.hl7.fhir.r5.model.Enumerations.FHIRVersion._4_3_0);
break;
case _4_3_0_CIBUILD:
tgt.setValue(org.hl7.fhir.r5.model.Enumerations.FHIRVersion._4_3_0CIBUILD);
break;
case _4_3_0_SNAPSHOT1:
tgt.setValue(org.hl7.fhir.r5.model.Enumerations.FHIRVersion._4_3_0SNAPSHOT1);
break;
case _5_0_0:
tgt.setValue(org.hl7.fhir.r5.model.Enumerations.FHIRVersion._5_0_0);
break;
@ -254,6 +248,15 @@ public class Enumerations40_50 {
case _5_0_0DRAFTFINAL:
tgt.setValue(org.hl7.fhir.r5.model.Enumerations.FHIRVersion._5_0_0DRAFTFINAL);
break;
case _6_0_0:
tgt.setValue(org.hl7.fhir.r5.model.Enumerations.FHIRVersion._6_0_0);
break;
case _6_0_0_BALLOT1:
tgt.setValue(org.hl7.fhir.r5.model.Enumerations.FHIRVersion._6_0_0_BALLOT1);
break;
case _6_0_0_BALLOT2:
tgt.setValue(org.hl7.fhir.r5.model.Enumerations.FHIRVersion._6_0_0_BALLOT2);
break;
default:
tgt.setValue(org.hl7.fhir.r5.model.Enumerations.FHIRVersion.NULL);
break;
@ -342,12 +345,6 @@ public class Enumerations40_50 {
case _4_3_0:
tgt.setValue(org.hl7.fhir.r4.model.Enumerations.FHIRVersion._4_3_0);
break;
case _4_3_0CIBUILD:
tgt.setValue(org.hl7.fhir.r4.model.Enumerations.FHIRVersion._4_3_0_CIBUILD);
break;
case _4_3_0SNAPSHOT1:
tgt.setValue(org.hl7.fhir.r4.model.Enumerations.FHIRVersion._4_3_0_SNAPSHOT1);
break;
case _5_0_0:
tgt.setValue(org.hl7.fhir.r4.model.Enumerations.FHIRVersion._5_0_0);
break;
@ -366,6 +363,15 @@ public class Enumerations40_50 {
case _5_0_0DRAFTFINAL:
tgt.setValue(org.hl7.fhir.r4.model.Enumerations.FHIRVersion._5_0_0DRAFTFINAL);
break;
case _6_0_0:
tgt.setValue(org.hl7.fhir.r4.model.Enumerations.FHIRVersion._6_0_0);
break;
case _6_0_0_BALLOT1:
tgt.setValue(org.hl7.fhir.r4.model.Enumerations.FHIRVersion._6_0_0_BALLOT1);
break;
case _6_0_0_BALLOT2:
tgt.setValue(org.hl7.fhir.r4.model.Enumerations.FHIRVersion._6_0_0_BALLOT2);
break;
default:
tgt.setValue(org.hl7.fhir.r4.model.Enumerations.FHIRVersion.NULL);

View File

@ -33,9 +33,11 @@ import org.hl7.fhir.convertors.factory.VersionConvertorFactory_30_40;
import org.hl7.fhir.convertors.factory.VersionConvertorFactory_30_50;
import org.hl7.fhir.convertors.factory.VersionConvertorFactory_40_50;
import org.hl7.fhir.r5.model.Enumeration;
import org.hl7.fhir.r5.model.Enumerations.FHIRVersion;
import org.hl7.fhir.r5.model.Enumerations.FHIRVersionEnumFactory;
import org.hl7.fhir.r5.model.ImplementationGuide;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
@ -237,7 +239,7 @@ public class NpmPackageVersionConverter {
return new org.hl7.fhir.dstu2016may.formats.JsonParser().composeBytes(VersionConvertorFactory_14_30.convertResource(VersionConvertorFactory_10_30.convertResource(res)));
} else if (VersionUtilities.isR3Ver(version)) {
return new org.hl7.fhir.dstu3.formats.JsonParser().composeBytes(VersionConvertorFactory_10_30.convertResource(res));
} else if (VersionUtilities.isR4Ver(version)) {
} else if (VersionUtilities.isR4Ver(version) || VersionUtilities.isR4BVer(version)) {
return new org.hl7.fhir.r4.formats.JsonParser().composeBytes(VersionConvertorFactory_10_40.convertResource(res));
} else if (VersionUtilities.isR5Plus(version)) {
return new org.hl7.fhir.r5.formats.JsonParser().composeBytes(VersionConvertorFactory_10_50.convertResource(res));
@ -251,7 +253,7 @@ public class NpmPackageVersionConverter {
return new org.hl7.fhir.dstu2016may.formats.JsonParser().composeBytes(res);
} else if (VersionUtilities.isR3Ver(version)) {
return new org.hl7.fhir.dstu3.formats.JsonParser().composeBytes(VersionConvertorFactory_14_30.convertResource(res));
} else if (VersionUtilities.isR4Ver(version)) {
} else if (VersionUtilities.isR4Ver(version) || VersionUtilities.isR4BVer(version)) {
return new org.hl7.fhir.r4.formats.JsonParser().composeBytes(VersionConvertorFactory_14_40.convertResource(res));
} else if (VersionUtilities.isR5Plus(version)) {
return new org.hl7.fhir.r5.formats.JsonParser().composeBytes(VersionConvertorFactory_14_50.convertResource(res));
@ -265,7 +267,7 @@ public class NpmPackageVersionConverter {
return new org.hl7.fhir.dstu2016may.formats.JsonParser().composeBytes(VersionConvertorFactory_14_30.convertResource(res));
} else if (VersionUtilities.isR3Ver(version)) {
return new org.hl7.fhir.dstu3.formats.JsonParser().composeBytes(res);
} else if (VersionUtilities.isR4Ver(version)) {
} else if (VersionUtilities.isR4Ver(version) || VersionUtilities.isR4BVer(version)) {
return new org.hl7.fhir.r4.formats.JsonParser().composeBytes(VersionConvertorFactory_30_40.convertResource(res));
} else if (VersionUtilities.isR5Plus(version)) {
return new org.hl7.fhir.r5.formats.JsonParser().composeBytes(VersionConvertorFactory_30_50.convertResource(res));
@ -279,7 +281,21 @@ public class NpmPackageVersionConverter {
return new org.hl7.fhir.dstu2016may.formats.JsonParser().composeBytes(VersionConvertorFactory_14_40.convertResource(res));
} else if (VersionUtilities.isR3Ver(version)) {
return new org.hl7.fhir.dstu3.formats.JsonParser().composeBytes(VersionConvertorFactory_30_40.convertResource(res, new BaseAdvisor_30_40(false)));
} else if (VersionUtilities.isR4Ver(version)) {
} else if (VersionUtilities.isR4Ver(version) || VersionUtilities.isR4BVer(version)) {
return new org.hl7.fhir.r4.formats.JsonParser().composeBytes(res);
} else if (VersionUtilities.isR5Plus(version)) {
return new org.hl7.fhir.r5.formats.JsonParser().composeBytes(VersionConvertorFactory_40_50.convertResource(res));
}
} else if (VersionUtilities.isR4BVer(currentVersion)) {
org.hl7.fhir.r4.model.Resource res = new org.hl7.fhir.r4.formats.JsonParser().parse(cnt);
convertResourceR4B(res);
if (VersionUtilities.isR2Ver(version)) {
return new org.hl7.fhir.dstu2.formats.JsonParser().composeBytes(VersionConvertorFactory_10_40.convertResource(res, new PR2Handler()));
} else if (VersionUtilities.isR2BVer(version)) {
return new org.hl7.fhir.dstu2016may.formats.JsonParser().composeBytes(VersionConvertorFactory_14_40.convertResource(res));
} else if (VersionUtilities.isR3Ver(version)) {
return new org.hl7.fhir.dstu3.formats.JsonParser().composeBytes(VersionConvertorFactory_30_40.convertResource(res, new BaseAdvisor_30_40(false)));
} else if (VersionUtilities.isR4Ver(version) || VersionUtilities.isR4BVer(version)) {
return new org.hl7.fhir.r4.formats.JsonParser().composeBytes(res);
} else if (VersionUtilities.isR5Plus(version)) {
return new org.hl7.fhir.r5.formats.JsonParser().composeBytes(VersionConvertorFactory_40_50.convertResource(res));
@ -293,7 +309,7 @@ public class NpmPackageVersionConverter {
return new org.hl7.fhir.dstu2016may.formats.JsonParser().composeBytes(VersionConvertorFactory_14_50.convertResource(res));
} else if (VersionUtilities.isR3Ver(version)) {
return new org.hl7.fhir.dstu3.formats.JsonParser().composeBytes(VersionConvertorFactory_30_50.convertResource(res, new BaseAdvisor_30_50(false)));
} else if (VersionUtilities.isR4Ver(version)) {
} else if (VersionUtilities.isR4Ver(version) || VersionUtilities.isR4BVer(version)) {
return new org.hl7.fhir.r4.formats.JsonParser().composeBytes(VersionConvertorFactory_40_50.convertResource(res));
} else if (VersionUtilities.isR5Plus(version)) {
return new org.hl7.fhir.r5.formats.JsonParser().composeBytes(res);
@ -311,6 +327,10 @@ public class NpmPackageVersionConverter {
org.hl7.fhir.dstu2.model.ImplementationGuide ig = (org.hl7.fhir.dstu2.model.ImplementationGuide) res;
ig.setFhirVersion(version);
}
if (res instanceof org.hl7.fhir.dstu2.model.StructureDefinition) {
org.hl7.fhir.dstu2.model.StructureDefinition sd = (org.hl7.fhir.dstu2.model.StructureDefinition) res;
sd.setFhirVersion(version);
}
}
private void convertResourceR2B(org.hl7.fhir.dstu2016may.model.Resource res) {
@ -318,6 +338,10 @@ public class NpmPackageVersionConverter {
org.hl7.fhir.dstu2016may.model.ImplementationGuide ig = (org.hl7.fhir.dstu2016may.model.ImplementationGuide) res;
ig.setFhirVersion(version);
}
if (res instanceof org.hl7.fhir.dstu2016may.model.StructureDefinition) {
org.hl7.fhir.dstu2016may.model.StructureDefinition sd = (org.hl7.fhir.dstu2016may.model.StructureDefinition) res;
sd.setFhirVersion(version);
}
}
private void convertResourceR3(org.hl7.fhir.dstu3.model.Resource res) {
@ -325,6 +349,10 @@ public class NpmPackageVersionConverter {
org.hl7.fhir.dstu3.model.ImplementationGuide ig = (org.hl7.fhir.dstu3.model.ImplementationGuide) res;
ig.setFhirVersion(version);
}
if (res instanceof org.hl7.fhir.dstu3.model.StructureDefinition) {
org.hl7.fhir.dstu3.model.StructureDefinition sd = (org.hl7.fhir.dstu3.model.StructureDefinition) res;
sd.setFhirVersion(version);
}
}
private void convertResourceR4(org.hl7.fhir.r4.model.Resource res) {
@ -334,6 +362,23 @@ public class NpmPackageVersionConverter {
ig.getFhirVersion().add(new org.hl7.fhir.r4.model.Enumeration<>(new org.hl7.fhir.r4.model.Enumerations.FHIRVersionEnumFactory(), version));
ig.setPackageId(packageId);
}
if (res instanceof org.hl7.fhir.r4.model.StructureDefinition) {
org.hl7.fhir.r4.model.StructureDefinition sd = (org.hl7.fhir.r4.model.StructureDefinition) res;
sd.setFhirVersion(org.hl7.fhir.r4.model.Enumerations.FHIRVersion.fromCode(version));
}
}
private void convertResourceR4B(org.hl7.fhir.r4.model.Resource res) {
if (res instanceof org.hl7.fhir.r4.model.ImplementationGuide) {
org.hl7.fhir.r4.model.ImplementationGuide ig = (org.hl7.fhir.r4.model.ImplementationGuide) res;
ig.getFhirVersion().clear();
ig.getFhirVersion().add(new org.hl7.fhir.r4.model.Enumeration<>(new org.hl7.fhir.r4.model.Enumerations.FHIRVersionEnumFactory(), version));
ig.setPackageId(packageId);
}
if (res instanceof org.hl7.fhir.r4.model.StructureDefinition) {
org.hl7.fhir.r4.model.StructureDefinition sd = (org.hl7.fhir.r4.model.StructureDefinition) res;
sd.setFhirVersion(org.hl7.fhir.r4.model.Enumerations.FHIRVersion.fromCode(version));
}
}
@ -344,6 +389,10 @@ public class NpmPackageVersionConverter {
ig.getFhirVersion().add(new Enumeration<>(new FHIRVersionEnumFactory(), version));
ig.setPackageId(packageId);
}
if (res instanceof StructureDefinition) {
StructureDefinition sd = (StructureDefinition) res;
sd.setFhirVersion(FHIRVersion.fromCode(version));
}
}
}

View File

@ -45,10 +45,10 @@ public class VSACImporter extends OIDBasedValueSetImporter {
public static void main(String[] args) throws FHIRException, IOException, ParseException, URISyntaxException {
VSACImporter self = new VSACImporter();
self.process(args[0], args[1], args[2], "true".equals(args[3]));
self.process(args[0], args[1], args[2], "true".equals(args[3]), "true".equals(args[4]));
}
private void process(String source, String dest, String apiKey, boolean onlyNew) throws FHIRException, IOException, URISyntaxException {
private void process(String source, String dest, String apiKey, boolean onlyNew, boolean onlyActive) throws FHIRException, IOException, URISyntaxException {
CSVReader csv = new CSVReader(ManagedFileAccess.inStream(source));
csv.readHeaders();
Map<String, String> errs = new HashMap<>();
@ -75,13 +75,20 @@ public class VSACImporter extends OIDBasedValueSetImporter {
System.out.println("Loading");
List<String> oids = new ArrayList<>();
List<String> allOids = new ArrayList<>();
while (csv.line()) {
String oid = csv.cell("OID");
if (!onlyNew || !(ManagedFileAccess.file(Utilities.path(dest, "ValueSet-" + oid + ".json")).exists())) {
oids.add(oid);
String status = csv.cell("Expansion Status");
if (!onlyActive || "Active".equals(status)) {
String oid = csv.cell("OID");
allOids.add(oid);
if (!onlyNew || !(ManagedFileAccess.file(Utilities.path(dest, "ValueSet-" + oid + ".json")).exists())) {
oids.add(oid);
}
}
}
Collections.sort(oids);
System.out.println("Cleaning");
cleanValueSets(allOids, dest);
System.out.println("Go: "+oids.size()+" oids");
int i = 0;
int j = 0;
@ -108,6 +115,7 @@ public class VSACImporter extends OIDBasedValueSetImporter {
errs.put(oid, e.getMessage());
}
}
OperationOutcome oo = new OperationOutcome();
for (String oid : errs.keySet()) {
oo.addIssue().setSeverity(IssueSeverity.ERROR).setCode(IssueType.EXCEPTION).setDiagnostics(errs.get(oid)).addLocation(oid);
@ -116,6 +124,22 @@ public class VSACImporter extends OIDBasedValueSetImporter {
System.out.println("Done. " + i + " ValueSets in "+Utilities.describeDuration(System.currentTimeMillis() - tt));
}
private void cleanValueSets(List<String> allOids, String dest) throws IOException {
cleanValueSets(allOids, new File(Utilities.path(dest)));
}
private void cleanValueSets(List<String> allOids, File file) {
for (File f : file.listFiles()) {
if (f.getName().startsWith("ValueSet-")) {
String oid = f.getName().substring(9).replace(".json", "");
if (!allOids.contains(oid)) {
f.delete();
}
}
}
}
private long estimate(int i, int size, long tt) {
long elapsed = System.currentTimeMillis() - tt;
long average = elapsed / i;
@ -201,7 +225,7 @@ public class VSACImporter extends OIDBasedValueSetImporter {
}
vs.setName(makeValidName(vs.getName()));
JurisdictionUtilities.setJurisdictionCountry(vs.getJurisdiction(), "US");
new JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(ManagedFileAccess.outStream(Utilities.path(dest, "ValueSet-" + oid + ".json")), vs);
new JsonParser().setOutputStyle(OutputStyle.NORMAL).compose(ManagedFileAccess.outStream(Utilities.path(dest, "ValueSet-" + oid + ".json")), vs);
return true;
}
}

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.27-SNAPSHOT</version>
<version>6.3.30-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -683,7 +683,7 @@ public class ClientUtils {
for (Header h : response.getAllHeaders()) {
headers.add(h.toString());
}
logger.logResponse(response.getStatusLine().toString(), headers, cnt);
logger.logResponse(response.getStatusLine().toString(), headers, cnt, 0);
}
return cnt;
}

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.27-SNAPSHOT</version>
<version>6.3.30-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -625,7 +625,7 @@ public class ClientUtils {
for (Header h : response.getAllHeaders()) {
headers.add(h.toString());
}
logger.logResponse(response.getStatusLine().toString(), headers, cnt);
logger.logResponse(response.getStatusLine().toString(), headers, cnt, 0);
}
return cnt;
}

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.27-SNAPSHOT</version>
<version>6.3.30-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -371,7 +371,7 @@ public class FhirRequestBuilder {
try {
if (logger != null) {
logger.logResponse(Integer.toString(responseCode), headerList, responseBody);
logger.logResponse(Integer.toString(responseCode), headerList, responseBody, 0);
}
} catch (Exception e) {
System.out.println("Error parsing response body passed in to logger ->\n" + e.getLocalizedMessage());

View File

@ -95,13 +95,13 @@ public class FhirRequestBuilderTests {
Mockito.doReturn(parser).when(fhirRequestBuilder).getParser(ArgumentMatchers.eq("json"));
fhirRequestBuilder.unmarshalReference(response, "json");
Mockito.verify(logger).logResponse(ArgumentMatchers.eq("200"), ArgumentMatchers.anyList(), AdditionalMatchers.aryEq(RESPONSE_BODY_STRING.getBytes()));
Mockito.verify(logger).logResponse(ArgumentMatchers.eq("200"), ArgumentMatchers.anyList(), AdditionalMatchers.aryEq(RESPONSE_BODY_STRING.getBytes()), ArgumentMatchers.anyLong());
}
@Test
public void testUnmarshallFeedLogging() {
fhirRequestBuilder.unmarshalFeed(response, "application/json");
Mockito.verify(logger).logResponse(ArgumentMatchers.eq("200"), ArgumentMatchers.anyList(), AdditionalMatchers.aryEq(RESPONSE_BODY_STRING.getBytes()));
Mockito.verify(logger).logResponse(ArgumentMatchers.eq("200"), ArgumentMatchers.anyList(), AdditionalMatchers.aryEq(RESPONSE_BODY_STRING.getBytes()), ArgumentMatchers.anyLong());
}
}

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.27-SNAPSHOT</version>
<version>6.3.30-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -77,7 +77,7 @@ public class HTMLClientLogger implements ToolingClientLogger {
}
@Override
public void logResponse(String outcome, List<String> headers, byte[] body) {
public void logResponse(String outcome, List<String> headers, byte[] body, long start) {
if (file == null)
return;
file.println("<pre>");

View File

@ -64,7 +64,7 @@ public class FhirLoggingInterceptor implements Interceptor {
headerMap.keySet().forEach(key -> headerMap.get(key).forEach(value -> headerList.add(key + ":" + value)));
if (logger != null) {
logger.logResponse(Integer.toString(response.code()), headerList, bodyBytes);
logger.logResponse(Integer.toString(response.code()), headerList, bodyBytes, 0);
}
// Reading byte[] clears body. Need to recreate.

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.27-SNAPSHOT</version>
<version>6.3.30-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -85,7 +85,7 @@ public class HTMLClientLogger extends BaseLogger implements ToolingClientLogger
}
@Override
public void logResponse(String outcome, List<String> headers, byte[] body) {
public void logResponse(String outcome, List<String> headers, byte[] body, long start) {
if (DEBUG) {
System.out.println(" txlog resp: " + outcome + " " + present(body));
}

View File

@ -72,7 +72,7 @@ public class TextClientLogger extends BaseLogger implements ToolingClientLogger
}
@Override
public void logResponse(String outcome, List<String> headers, byte[] body) {
public void logResponse(String outcome, List<String> headers, byte[] body, long start) {
if (file == null)
return;
file.println("\r\n\r\nResponse: \r\n");

View File

@ -59,7 +59,7 @@ public class FhirLoggingInterceptor implements Interceptor {
headerMap.keySet().forEach(key -> headerMap.get(key).forEach(value -> headerList.add(key + ":" + value)));
if (logger != null) {
logger.logResponse(Integer.toString(response.code()), headerList, bodyBytes);
logger.logResponse(Integer.toString(response.code()), headerList, bodyBytes, 0);
}
// Reading byte[] clears body. Need to recreate.

View File

@ -134,6 +134,6 @@ class ClientTest {
server.takeRequest();
Mockito.verify(mockLogger, Mockito.times(1)).logRequest(Mockito.anyString(), Mockito.anyString(), Mockito.anyList(),
Mockito.any());
Mockito.verify(mockLogger, Mockito.times(1)).logResponse(Mockito.anyString(), Mockito.anyList(), Mockito.any());
Mockito.verify(mockLogger, Mockito.times(1)).logResponse(Mockito.anyString(), Mockito.anyList(), Mockito.any(), Mockito.anyLong());
}
}

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.27-SNAPSHOT</version>
<version>6.3.30-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -2923,7 +2923,7 @@ public class ProfileUtilities {
private ElementDefinitionBindingAdditionalComponent getMatchingAdditionalBinding(ElementDefinitionBindingComponent nb,ElementDefinitionBindingAdditionalComponent ab) {
for (ElementDefinitionBindingAdditionalComponent t : nb.getAdditional()) {
if (t.getValueSet() != null && t.getValueSet().equals(ab.getValueSet()) && t.getPurpose() == ab.getPurpose()) {
if (t.getValueSet() != null && t.getValueSet().equals(ab.getValueSet()) && t.getPurpose() == ab.getPurpose() && !ab.hasUsage()) {
return t;
}
}
@ -4579,6 +4579,7 @@ public class ProfileUtilities {
public void setMessages(List<ValidationMessage> messages) {
if (messages != null) {
this.messages = messages;
wantThrowExceptions = false;
}
}

View File

@ -1276,9 +1276,9 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
}
public ValidationResult validateCode(final ValidationOptions optionsArg, String path, final Coding code, final ValueSet vs, final ValidationContextCarrier ctxt) {
ValidationOptions options = optionsArg != null ? optionsArg : ValidationOptions.defaults();
if (code.hasSystem()) {
codeSystemsUsed.add(code.getSystem());
}
@ -1303,6 +1303,9 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
// ok, first we try to validate locally
try {
ValueSetValidator vsc = constructValueSetCheckerSimple(options, vs, ctxt);
if (vsc.getOpContext() != null) {
vsc.getOpContext().note("Validate "+code.toString()+" @ "+path+" against "+(vs == null ? "null" : vs.getVersionedUrl()));
}
vsc.setUnknownSystems(unknownSystems);
vsc.setThrowToServer(options.isUseServer() && terminologyClientManager.hasClient());
if (!ValueSetUtilities.isServerSide(code.getSystem())) {
@ -1471,15 +1474,15 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
}
protected ValueSetExpander constructValueSetExpanderSimple(ValidationOptions options) {
return new ValueSetExpander(this, new TerminologyOperationContext(this, options)).setDebug(logger.isDebugLogging());
return new ValueSetExpander(this, new TerminologyOperationContext(this, options, "expansion")).setDebug(logger.isDebugLogging());
}
protected ValueSetValidator constructValueSetCheckerSimple(ValidationOptions options, ValueSet vs, ValidationContextCarrier ctxt) {
return new ValueSetValidator(this, new TerminologyOperationContext(this, options), options, vs, ctxt, expParameters, terminologyClientManager);
return new ValueSetValidator(this, new TerminologyOperationContext(this, options, "validation"), options, vs, ctxt, expParameters, terminologyClientManager);
}
protected ValueSetValidator constructValueSetCheckerSimple( ValidationOptions options, ValueSet vs) {
return new ValueSetValidator(this, new TerminologyOperationContext(this, options), options, vs, expParameters, terminologyClientManager);
return new ValueSetValidator(this, new TerminologyOperationContext(this, options, "validation"), options, vs, expParameters, terminologyClientManager);
}
protected Parameters constructParameters(TerminologyClientContext tcd, ValueSet vs, boolean hierarchical) {
@ -1643,7 +1646,11 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
Parameters pIn = constructParameters(options, code);
res = validateOnServer(tc, vs, pIn, options);
} catch (Exception e) {
res = new ValidationResult(IssueSeverity.ERROR, e.getMessage() == null ? e.getClass().getName() : e.getMessage(), null).setTxLink(txLog == null ? null : txLog.getLastId());
issues.clear();
OperationOutcomeIssueComponent iss = new OperationOutcomeIssueComponent(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR, org.hl7.fhir.r5.model.OperationOutcome.IssueType.EXCEPTION);
iss.getDetails().setText(e.getMessage());
issues.add(iss);
res = new ValidationResult(IssueSeverity.ERROR, e.getMessage() == null ? e.getClass().getName() : e.getMessage(), issues).setTxLink(txLog == null ? null : txLog.getLastId()).setErrorClass(TerminologyServiceErrorClass.SERVER_ERROR);
}
if (cachingAllowed) {
txCache.cacheValidation(cacheToken, res, TerminologyCache.PERMANENT);
@ -1779,6 +1786,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
if (options.isDisplayWarningMode()) {
pin.addParameter("mode","lenient-display-validation");
}
pin.addParameter("diagnostics", true);
}
private boolean addDependentResources(TerminologyClientContext tc, Parameters pin, ValueSet vs) {

View File

@ -87,7 +87,7 @@ public class HTMLClientLogger extends BaseLogger implements ToolingClientLogger
}
@Override
public void logResponse(String outcome, List<String> headers, byte[] body) {
public void logResponse(String outcome, List<String> headers, byte[] body, long start) {
if (DEBUG) {
System.out.println(" txlog resp: " +outcome+" "+present(body));
}

View File

@ -76,10 +76,10 @@ public class TextClientLogger extends BaseLogger implements ToolingClientLogger
}
@Override
public void logResponse(String outcome, List<String> headers, byte[] body) {
public void logResponse(String outcome, List<String> headers, byte[] body, long length) {
if (file == null)
return;
file.println("\r\n\r\nResponse: \r\n");
file.println("\r\n\r\nResponse ("+Utilities.describeDuration(length)+"): \r\n");
file.println(outcome);
for (String s : headers)
file.println(s);

View File

@ -162,6 +162,7 @@ public class Element extends Base implements NamedItem {
private FhirFormat format;
private Object nativeObject;
private List<SliceDefinition> sliceDefinitions;
private boolean elided;
public Element(String name) {
super();
@ -1429,6 +1430,8 @@ public class Element extends Base implements NamedItem {
public Base copy() {
Element element = new Element(this);
this.copyValues(element);
if (this.isElided())
element.setElided(true);
return element;
}
@ -1638,4 +1641,11 @@ public class Element extends Base implements NamedItem {
return FhirPublication.fromCode(property.getStructure().getVersion());
}
public void setElided(boolean elided) {
this.elided = elided;
}
public boolean isElided() {
return this.elided;
}
}

View File

@ -62,6 +62,7 @@ import org.hl7.fhir.r5.formats.JsonCreatorDirect;
import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent;
import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.StringPair;
import org.hl7.fhir.utilities.TextFile;
@ -85,6 +86,8 @@ public class JsonParser extends ParserBase {
private JsonCreator json;
private boolean allowComments;
private boolean elideElements;
// private boolean suppressResourceType;
private Element baseElement;
private boolean markedXhtml;
@ -782,7 +785,8 @@ public class JsonParser extends ParserBase {
}
checkComposeComments(e);
json.beginObject();
prop("resourceType", e.getType(), null);
// if (!isSuppressResourceType())
prop("resourceType", e.getType(), null);
Set<String> done = new HashSet<String>();
for (Element child : e.getChildren()) {
compose(e.getName(), e, done, child);
@ -807,7 +811,8 @@ public class JsonParser extends ParserBase {
checkComposeComments(e);
json.beginObject();
prop("resourceType", e.getType(), linkResolver == null ? null : linkResolver.resolveProperty(e.getProperty()));
// if (!isSuppressResourceType())
prop("resourceType", e.getType(), linkResolver == null ? null : linkResolver.resolveProperty(e.getProperty()));
Set<String> done = new HashSet<String>();
for (Element child : e.getChildren()) {
compose(e.getName(), e, done, child);
@ -821,15 +826,50 @@ public class JsonParser extends ParserBase {
if (wantCompose(path, child)) {
boolean isList = child.hasElementProperty() ? child.getElementProperty().isList() : child.getProperty().isList();
if (!isList) {// for specials, ignore the cardinality of the stated type
compose(path, child);
if (child.isElided() && isElideElements() && json.canElide())
json.elide();
else
compose(path, child);
} else if (!done.contains(child.getName())) {
done.add(child.getName());
List<Element> list = e.getChildrenByName(child.getName());
composeList(path, list);
if (child.getProperty().getDefinition().hasExtension(ToolingExtensions.EXT_JSON_PROP_KEY))
composeKeyList(path, list);
else
composeList(path, list);
}
}
}
private void composeKeyList(String path, List<Element> list) throws IOException {
String keyName = list.get(0).getProperty().getDefinition().getExtensionString(ToolingExtensions.EXT_JSON_PROP_KEY);
json.name(list.get(0).getName());
json.beginObject();
for (Element e: list) {
Element key = null;
Element value = null;
for (Element child: e.getChildren()) {
if (child.getName().equals(keyName))
key = child;
else
value = child;
}
if (value.isPrimitive())
primitiveValue(key.getValue(), value);
else {
json.name(key.getValue());
checkComposeComments(e);
json.beginObject();
Set<String> done = new HashSet<String>();
for (Element child : value.getChildren()) {
compose(value.getName(), value, done, child);
}
json.endObject();
compose(path + "." + key.getValue(), value);
}
}
json.endObject();
}
private void composeList(String path, List<Element> list) throws IOException {
// there will be at least one element
@ -847,7 +887,9 @@ public class JsonParser extends ParserBase {
if (prim) {
openArray(name, linkResolver == null ? null : linkResolver.resolveProperty(list.get(0).getProperty()));
for (Element item : list) {
if (item.hasValue()) {
if (item.isElided() && json.canElide())
json.elide();
else if (item.hasValue()) {
if (linkResolver != null && item.getProperty().isReference()) {
String ref = linkResolver.resolveReference(getReferenceForElement(item));
if (ref != null) {
@ -866,7 +908,9 @@ public class JsonParser extends ParserBase {
openArray(name, linkResolver == null ? null : linkResolver.resolveProperty(list.get(0).getProperty()));
int i = 0;
for (Element item : list) {
if (item.hasChildren()) {
if (item.isElided() && json.canElide())
json.elide();
else if (item.hasChildren()) {
open(null,null);
if (item.getProperty().isResource()) {
prop("resourceType", item.getType(), linkResolver == null ? null : linkResolver.resolveType(item.getType()));
@ -933,9 +977,10 @@ public class JsonParser extends ParserBase {
json.externalLink(ref);
}
}
Set<String> done = new HashSet<String>();
for (Element child : element.getChildren()) {
compose(path+"."+element.getName(), element, done, child);
compose(path + "." + element.getName(), element, done, child);
}
close();
}
@ -951,5 +996,23 @@ public class JsonParser extends ParserBase {
return this;
}
public boolean isElideElements() {
return elideElements;
}
public JsonParser setElideElements(boolean elideElements) {
this.elideElements = elideElements;
return this;
}
/*
public boolean isSuppressResourceType() {
return suppressResourceType;
}
public JsonParser setSuppressResourceType(boolean suppressResourceType) {
this.suppressResourceType = suppressResourceType;
return this;
}
*/
}

View File

@ -94,6 +94,7 @@ import org.xml.sax.XMLReader;
public class XmlParser extends ParserBase {
private boolean allowXsiLocation;
private String version;
private boolean elideElements;
public XmlParser(IWorkerContext context) {
super(context);
@ -805,92 +806,125 @@ public class XmlParser extends ParserBase {
}
private void composeElement(IXMLWriter xml, Element element, String elementName, boolean root) throws IOException, FHIRException {
if (showDecorations) {
@SuppressWarnings("unchecked")
List<ElementDecoration> decorations = (List<ElementDecoration>) element.getUserData("fhir.decorations");
if (decorations != null)
for (ElementDecoration d : decorations)
xml.decorate(d);
}
for (String s : element.getComments()) {
xml.comment(s, true);
if (!(isElideElements() && element.isElided())) {
if (showDecorations) {
@SuppressWarnings("unchecked")
List<ElementDecoration> decorations = (List<ElementDecoration>) element.getUserData("fhir.decorations");
if (decorations != null)
for (ElementDecoration d : decorations)
xml.decorate(d);
}
for (String s : element.getComments()) {
xml.comment(s, true);
}
}
if (isText(element.getProperty())) {
if (linkResolver != null)
xml.link(linkResolver.resolveProperty(element.getProperty()));
xml.enter(element.getProperty().getXmlNamespace(),elementName);
if (linkResolver != null && element.getProperty().isReference()) {
String ref = linkResolver.resolveReference(getReferenceForElement(element));
if (ref != null) {
xml.externalLink(ref);
if (isElideElements() && element.isElided() && xml.canElide())
xml.elide();
else {
if (linkResolver != null)
xml.link(linkResolver.resolveProperty(element.getProperty()));
xml.enter(element.getProperty().getXmlNamespace(),elementName);
if (linkResolver != null && element.getProperty().isReference()) {
String ref = linkResolver.resolveReference(getReferenceForElement(element));
if (ref != null) {
xml.externalLink(ref);
}
}
xml.text(element.getValue());
xml.exit(element.getProperty().getXmlNamespace(),elementName);
}
xml.text(element.getValue());
xml.exit(element.getProperty().getXmlNamespace(),elementName);
} else if (!element.hasChildren() && !element.hasValue()) {
if (element.getExplicitType() != null)
xml.attribute("xsi:type", element.getExplicitType());
xml.element(elementName);
if (isElideElements() && element.isElided() && xml.canElide())
xml.elide();
else {
if (element.getExplicitType() != null)
xml.attribute("xsi:type", element.getExplicitType());
xml.element(elementName);
}
} else if (element.isPrimitive() || (element.hasType() && isPrimitive(element.getType()))) {
if (element.getType().equals("xhtml")) {
String rawXhtml = element.getValue();
if (isCdaText(element.getProperty())) {
new CDANarrativeFormat().convert(xml, new XhtmlParser().parseFragment(rawXhtml));
} else {
xml.escapedText(rawXhtml);
if (!markedXhtml) {
xml.anchor("end-xhtml");
markedXhtml = true;
if (isElideElements() && element.isElided() && xml.canElide())
xml.elide();
else {
String rawXhtml = element.getValue();
if (isCdaText(element.getProperty())) {
new CDANarrativeFormat().convert(xml, new XhtmlParser().parseFragment(rawXhtml));
} else {
xml.escapedText(rawXhtml);
if (!markedXhtml) {
xml.anchor("end-xhtml");
markedXhtml = true;
}
}
}
} else if (isText(element.getProperty())) {
if (linkResolver != null)
xml.link(linkResolver.resolveProperty(element.getProperty()));
xml.text(element.getValue());
} else {
setXsiTypeIfIsTypeAttr(xml, element);
if (element.hasValue()) {
if (isElideElements() && element.isElided() && xml.canElide())
xml.elide();
else {
if (linkResolver != null)
xml.link(linkResolver.resolveType(element.getType()));
xml.attribute("value", element.getValue());
xml.link(linkResolver.resolveProperty(element.getProperty()));
xml.text(element.getValue());
}
if (linkResolver != null)
xml.link(linkResolver.resolveProperty(element.getProperty()));
if (element.hasChildren()) {
xml.enter(element.getProperty().getXmlNamespace(), elementName);
if (linkResolver != null && element.getProperty().isReference()) {
String ref = linkResolver.resolveReference(getReferenceForElement(element));
if (ref != null) {
xml.externalLink(ref);
}
} else {
if (isElideElements() && element.isElided())
xml.attributeElide();
else {
setXsiTypeIfIsTypeAttr(xml, element);
if (element.hasValue()) {
if (linkResolver != null)
xml.link(linkResolver.resolveType(element.getType()));
xml.attribute("value", element.getValue());
}
for (Element child : element.getChildren())
composeElement(xml, child, child.getName(), false);
xml.exit(element.getProperty().getXmlNamespace(),elementName);
} else
xml.element(elementName);
if (linkResolver != null)
xml.link(linkResolver.resolveProperty(element.getProperty()));
if (element.hasChildren()) {
xml.enter(element.getProperty().getXmlNamespace(), elementName);
if (linkResolver != null && element.getProperty().isReference()) {
String ref = linkResolver.resolveReference(getReferenceForElement(element));
if (ref != null) {
xml.externalLink(ref);
}
}
for (Element child : element.getChildren())
composeElement(xml, child, child.getName(), false);
xml.exit(element.getProperty().getXmlNamespace(),elementName);
} else
xml.element(elementName);
}
}
} else {
setXsiTypeIfIsTypeAttr(xml, element);
Set<String> handled = new HashSet<>();
if (isElideElements() && element.isElided() && xml.canElide())
xml.elide();
else {
setXsiTypeIfIsTypeAttr(xml, element);
Set<String> handled = new HashSet<>();
for (Element child : element.getChildren()) {
if (!handled.contains(child.getName()) && isAttr(child.getProperty()) && wantCompose(element.getPath(), child)) {
handled.add(child.getName());
String av = child.getValue();
if (child.getProperty().isList()) {
for (Element c2 : element.getChildren()) {
if (c2 != child && c2.getName().equals(child.getName())) {
av = av + " "+c2.getValue();
if (isElideElements() && child.isElided())
xml.attributeElide();
else {
String av = child.getValue();
if (child.getProperty().isList()) {
for (Element c2 : element.getChildren()) {
if (c2 != child && c2.getName().equals(child.getName())) {
if (c2.isElided())
av = av + " ...";
else
av = av + " " + c2.getValue();
}
}
}
}
if (linkResolver != null)
xml.link(linkResolver.resolveType(child.getType()));
if (ToolingExtensions.hasExtension(child.getProperty().getDefinition(), ToolingExtensions.EXT_DATE_FORMAT))
av = convertForDateFormatToExternal(ToolingExtensions.readStringExtension(child.getProperty().getDefinition(), ToolingExtensions.EXT_DATE_FORMAT), av);
xml.attribute(child.getProperty().getXmlNamespace(), child.getProperty().getXmlName(), av);
}
if (linkResolver != null)
xml.link(linkResolver.resolveType(child.getType()));
if (ToolingExtensions.hasExtension(child.getProperty().getDefinition(), ToolingExtensions.EXT_DATE_FORMAT))
av = convertForDateFormatToExternal(ToolingExtensions.readStringExtension(child.getProperty().getDefinition(), ToolingExtensions.EXT_DATE_FORMAT), av);
xml.attribute(child.getProperty().getXmlNamespace(),child.getProperty().getXmlName(), av);
}
}
}
if (!element.getProperty().getDefinition().hasExtension(ToolingExtensions.EXT_ID_CHOICE_GROUP)) {
if (linkResolver != null)
xml.link(linkResolver.resolveProperty(element.getProperty()));
@ -914,12 +948,16 @@ public class XmlParser extends ParserBase {
}
for (Element child : element.getChildren()) {
if (wantCompose(element.getPath(), child)) {
if (isText(child.getProperty())) {
if (linkResolver != null)
xml.link(linkResolver.resolveProperty(element.getProperty()));
xml.text(child.getValue());
} else if (!isAttr(child.getProperty())) {
composeElement(xml, child, child.getName(), false);
if (isElideElements() && child.isElided() && xml.canElide())
xml.elide();
else {
if (isText(child.getProperty())) {
if (linkResolver != null)
xml.link(linkResolver.resolveProperty(element.getProperty()));
xml.text(child.getValue());
} else if (!isAttr(child.getProperty())) {
composeElement(xml, child, child.getName(), false);
}
}
}
}
@ -1034,4 +1072,13 @@ public class XmlParser extends ParserBase {
// do nothing
}
}
public boolean isElideElements() {
return elideElements;
}
public void setElideElements(boolean elideElements) {
this.elideElements = elideElements;
}
}

View File

@ -1,5 +1,5 @@
package org.hl7.fhir.r5.formats;
package org.hl7.fhir.r5.formats;
/*
Copyright (c) 2011+, HL7, Inc.
All rights reserved.
@ -28,47 +28,49 @@ package org.hl7.fhir.r5.formats;
POSSIBILITY OF SUCH DAMAGE.
*/
import java.io.IOException;
import java.math.BigDecimal;
/**
* Facade to GSON writer, or something that imposes property ordering first
*
* @author Grahame
*
*/
public interface JsonCreator {
void comment(String comment);
void beginObject() throws IOException;
void endObject() throws IOException;
void nullValue() throws IOException;
void name(String name) throws IOException;
void value(String value) throws IOException;
void value(Boolean value) throws IOException;
void value(BigDecimal value) throws IOException;
void valueNum(String value) throws IOException; // allow full control of representation
void value(Integer value) throws IOException;
void beginArray() throws IOException;
void endArray() throws IOException;
void finish() throws IOException;
// only used by an creator that actually produces xhtml
void link(String href);
void anchor(String string);
void externalLink(String string);
import java.io.IOException;
import java.math.BigDecimal;
/**
* Facade to GSON writer, or something that imposes property ordering first
*
* @author Grahame
*
*/
public interface JsonCreator {
void comment(String comment);
void beginObject() throws IOException;
void endObject() throws IOException;
void nullValue() throws IOException;
void name(String name) throws IOException;
void value(String value) throws IOException;
void value(Boolean value) throws IOException;
void value(BigDecimal value) throws IOException;
void valueNum(String value) throws IOException; // allow full control of representation
void value(Integer value) throws IOException;
void beginArray() throws IOException;
void endArray() throws IOException;
void finish() throws IOException;
// only used by an creator that actually produces xhtml
void link(String href);
void anchor(String string);
void externalLink(String string);
void elide();
boolean canElide();
}

View File

@ -1,5 +1,5 @@
package org.hl7.fhir.r5.formats;
package org.hl7.fhir.r5.formats;
/*
Copyright (c) 2011+, HL7, Inc.
All rights reserved.
@ -28,257 +28,264 @@ package org.hl7.fhir.r5.formats;
POSSIBILITY OF SUCH DAMAGE.
*/
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Stack;
public class JsonCreatorCanonical implements JsonCreator {
public class JsonCanValue {
String name;
private JsonCanValue(String name) {
this.name = name;
}
}
private class JsonCanNumberValue extends JsonCanValue {
private BigDecimal value;
private JsonCanNumberValue(String name, BigDecimal value) {
super(name);
this.value = value;
}
}
private class JsonCanPresentedNumberValue extends JsonCanValue {
private String value;
private JsonCanPresentedNumberValue(String name, String value) {
super(name);
this.value = value;
}
}
private class JsonCanIntegerValue extends JsonCanValue {
private Integer value;
private JsonCanIntegerValue(String name, Integer value) {
super(name);
this.value = value;
}
}
private class JsonCanBooleanValue extends JsonCanValue {
private Boolean value;
private JsonCanBooleanValue(String name, Boolean value) {
super(name);
this.value = value;
}
}
private class JsonCanStringValue extends JsonCanValue {
private String value;
private JsonCanStringValue(String name, String value) {
super(name);
this.value = value;
}
}
private class JsonCanNullValue extends JsonCanValue {
private JsonCanNullValue(String name) {
super(name);
}
}
public class JsonCanObject extends JsonCanValue {
boolean array;
List<JsonCanValue> children = new ArrayList<JsonCanValue>();
public JsonCanObject(String name, boolean array) {
super(name);
this.array = array;
}
public void addProp(JsonCanValue obj) {
children.add(obj);
}
}
Stack<JsonCanObject> stack;
JsonCanObject root;
JsonCreatorDirect jj;
String name;
public JsonCreatorCanonical(OutputStreamWriter osw) {
stack = new Stack<JsonCreatorCanonical.JsonCanObject>();
jj = new JsonCreatorDirect(osw, false, false);
name = null;
}
private String takeName() {
String res = name;
name = null;
return res;
}
@Override
public void beginObject() throws IOException {
JsonCanObject obj = new JsonCanObject(takeName(), false);
if (stack.isEmpty())
root = obj;
else
stack.peek().addProp(obj);
stack.push(obj);
}
@Override
public void endObject() throws IOException {
stack.pop();
}
@Override
public void nullValue() throws IOException {
stack.peek().addProp(new JsonCanNullValue(takeName()));
}
@Override
public void name(String name) throws IOException {
this.name = name;
}
@Override
public void value(String value) throws IOException {
stack.peek().addProp(new JsonCanStringValue(takeName(), value));
}
@Override
public void value(Boolean value) throws IOException {
stack.peek().addProp(new JsonCanBooleanValue(takeName(), value));
}
@Override
public void value(BigDecimal value) throws IOException {
stack.peek().addProp(new JsonCanNumberValue(takeName(), value));
}
@Override
public void valueNum(String value) throws IOException {
stack.peek().addProp(new JsonCanPresentedNumberValue(takeName(), value));
}
@Override
public void value(Integer value) throws IOException {
stack.peek().addProp(new JsonCanIntegerValue(takeName(), value));
}
@Override
public void beginArray() throws IOException {
JsonCanObject obj = new JsonCanObject(takeName(), true);
if (!stack.isEmpty())
stack.peek().addProp(obj);
stack.push(obj);
}
@Override
public void endArray() throws IOException {
stack.pop();
}
@Override
public void finish() throws IOException {
writeObject(root);
}
private void writeObject(JsonCanObject obj) throws IOException {
jj.beginObject();
List<String> names = new ArrayList<String>();
for (JsonCanValue v : obj.children)
names.add(v.name);
Collections.sort(names);
for (String n : names) {
jj.name(n);
JsonCanValue v = getPropForName(n, obj.children);
if (v instanceof JsonCanNumberValue)
jj.value(((JsonCanNumberValue) v).value);
else if (v instanceof JsonCanPresentedNumberValue)
jj.valueNum(((JsonCanPresentedNumberValue) v).value);
else if (v instanceof JsonCanIntegerValue)
jj.value(((JsonCanIntegerValue) v).value);
else if (v instanceof JsonCanBooleanValue)
jj.value(((JsonCanBooleanValue) v).value);
else if (v instanceof JsonCanStringValue)
jj.value(((JsonCanStringValue) v).value);
else if (v instanceof JsonCanNullValue)
jj.nullValue();
else if (v instanceof JsonCanObject) {
JsonCanObject o = (JsonCanObject) v;
if (o.array)
writeArray(o);
else
writeObject(o);
} else
throw new Error("not possible");
}
jj.endObject();
}
private JsonCanValue getPropForName(String name, List<JsonCanValue> children) {
for (JsonCanValue child : children)
if (child.name.equals(name))
return child;
return null;
}
private void writeArray(JsonCanObject arr) throws IOException {
jj.beginArray();
for (JsonCanValue v : arr.children) {
if (v instanceof JsonCanNumberValue)
jj.value(((JsonCanNumberValue) v).value);
else if (v instanceof JsonCanIntegerValue)
jj.value(((JsonCanIntegerValue) v).value);
else if (v instanceof JsonCanBooleanValue)
jj.value(((JsonCanBooleanValue) v).value);
else if (v instanceof JsonCanStringValue)
jj.value(((JsonCanStringValue) v).value);
else if (v instanceof JsonCanNullValue)
jj.nullValue();
else if (v instanceof JsonCanObject) {
JsonCanObject o = (JsonCanObject) v;
if (o.array)
writeArray(o);
else
writeObject(o);
} else
throw new Error("not possible");
}
jj.endArray();
}
@Override
public void comment(String content) {
// canonical JSON ignores comments
}
@Override
public void link(String href) {
// not used
}
@Override
public void anchor(String name) {
// not used
}
@Override
public void externalLink(String string) {
// not used
}
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Stack;
public class JsonCreatorCanonical implements JsonCreator {
public class JsonCanValue {
String name;
private JsonCanValue(String name) {
this.name = name;
}
}
private class JsonCanNumberValue extends JsonCanValue {
private BigDecimal value;
private JsonCanNumberValue(String name, BigDecimal value) {
super(name);
this.value = value;
}
}
private class JsonCanPresentedNumberValue extends JsonCanValue {
private String value;
private JsonCanPresentedNumberValue(String name, String value) {
super(name);
this.value = value;
}
}
private class JsonCanIntegerValue extends JsonCanValue {
private Integer value;
private JsonCanIntegerValue(String name, Integer value) {
super(name);
this.value = value;
}
}
private class JsonCanBooleanValue extends JsonCanValue {
private Boolean value;
private JsonCanBooleanValue(String name, Boolean value) {
super(name);
this.value = value;
}
}
private class JsonCanStringValue extends JsonCanValue {
private String value;
private JsonCanStringValue(String name, String value) {
super(name);
this.value = value;
}
}
private class JsonCanNullValue extends JsonCanValue {
private JsonCanNullValue(String name) {
super(name);
}
}
public class JsonCanObject extends JsonCanValue {
boolean array;
List<JsonCanValue> children = new ArrayList<JsonCanValue>();
public JsonCanObject(String name, boolean array) {
super(name);
this.array = array;
}
public void addProp(JsonCanValue obj) {
children.add(obj);
}
}
Stack<JsonCanObject> stack;
JsonCanObject root;
JsonCreatorDirect jj;
String name;
public JsonCreatorCanonical(OutputStreamWriter osw) {
stack = new Stack<JsonCreatorCanonical.JsonCanObject>();
jj = new JsonCreatorDirect(osw, false, false);
name = null;
}
private String takeName() {
String res = name;
name = null;
return res;
}
@Override
public void beginObject() throws IOException {
JsonCanObject obj = new JsonCanObject(takeName(), false);
if (stack.isEmpty())
root = obj;
else
stack.peek().addProp(obj);
stack.push(obj);
}
@Override
public void endObject() throws IOException {
stack.pop();
}
@Override
public void nullValue() throws IOException {
stack.peek().addProp(new JsonCanNullValue(takeName()));
}
@Override
public void name(String name) throws IOException {
this.name = name;
}
@Override
public void value(String value) throws IOException {
stack.peek().addProp(new JsonCanStringValue(takeName(), value));
}
@Override
public void value(Boolean value) throws IOException {
stack.peek().addProp(new JsonCanBooleanValue(takeName(), value));
}
@Override
public void value(BigDecimal value) throws IOException {
stack.peek().addProp(new JsonCanNumberValue(takeName(), value));
}
@Override
public void valueNum(String value) throws IOException {
stack.peek().addProp(new JsonCanPresentedNumberValue(takeName(), value));
}
@Override
public void value(Integer value) throws IOException {
stack.peek().addProp(new JsonCanIntegerValue(takeName(), value));
}
@Override
public void beginArray() throws IOException {
JsonCanObject obj = new JsonCanObject(takeName(), true);
if (!stack.isEmpty())
stack.peek().addProp(obj);
stack.push(obj);
}
@Override
public void endArray() throws IOException {
stack.pop();
}
@Override
public void finish() throws IOException {
writeObject(root);
}
private void writeObject(JsonCanObject obj) throws IOException {
jj.beginObject();
List<String> names = new ArrayList<String>();
for (JsonCanValue v : obj.children)
names.add(v.name);
Collections.sort(names);
for (String n : names) {
jj.name(n);
JsonCanValue v = getPropForName(n, obj.children);
if (v instanceof JsonCanNumberValue)
jj.value(((JsonCanNumberValue) v).value);
else if (v instanceof JsonCanPresentedNumberValue)
jj.valueNum(((JsonCanPresentedNumberValue) v).value);
else if (v instanceof JsonCanIntegerValue)
jj.value(((JsonCanIntegerValue) v).value);
else if (v instanceof JsonCanBooleanValue)
jj.value(((JsonCanBooleanValue) v).value);
else if (v instanceof JsonCanStringValue)
jj.value(((JsonCanStringValue) v).value);
else if (v instanceof JsonCanNullValue)
jj.nullValue();
else if (v instanceof JsonCanObject) {
JsonCanObject o = (JsonCanObject) v;
if (o.array)
writeArray(o);
else
writeObject(o);
} else
throw new Error("not possible");
}
jj.endObject();
}
private JsonCanValue getPropForName(String name, List<JsonCanValue> children) {
for (JsonCanValue child : children)
if (child.name.equals(name))
return child;
return null;
}
private void writeArray(JsonCanObject arr) throws IOException {
jj.beginArray();
for (JsonCanValue v : arr.children) {
if (v instanceof JsonCanNumberValue)
jj.value(((JsonCanNumberValue) v).value);
else if (v instanceof JsonCanIntegerValue)
jj.value(((JsonCanIntegerValue) v).value);
else if (v instanceof JsonCanBooleanValue)
jj.value(((JsonCanBooleanValue) v).value);
else if (v instanceof JsonCanStringValue)
jj.value(((JsonCanStringValue) v).value);
else if (v instanceof JsonCanNullValue)
jj.nullValue();
else if (v instanceof JsonCanObject) {
JsonCanObject o = (JsonCanObject) v;
if (o.array)
writeArray(o);
else
writeObject(o);
} else
throw new Error("not possible");
}
jj.endArray();
}
@Override
public void comment(String content) {
// canonical JSON ignores comments
}
@Override
public void link(String href) {
// not used
}
@Override
public void anchor(String name) {
// not used
}
@Override
public void externalLink(String string) {
// not used
}
@Override
public boolean canElide() { return false; }
@Override
public void elide() {
// not used
}
}

View File

@ -1,5 +1,5 @@
package org.hl7.fhir.r5.formats;
package org.hl7.fhir.r5.formats;
/*
Copyright (c) 2011+, HL7, Inc.
All rights reserved.
@ -28,219 +28,227 @@ package org.hl7.fhir.r5.formats;
POSSIBILITY OF SUCH DAMAGE.
*/
import java.io.IOException;
import java.io.Writer;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import org.hl7.fhir.utilities.Utilities;
/**
* A little implementation of a json write to replace Gson .... because Gson screws up decimal values, and *we care*
*
* @author Grahame Grieve
*
*/
public class JsonCreatorDirect implements JsonCreator {
private Writer writer;
private boolean pretty;
private boolean comments;
private boolean named;
private List<Boolean> valued = new ArrayList<Boolean>();
private int indent;
private List<String> commentList = new ArrayList<>();
public JsonCreatorDirect(Writer writer, boolean pretty, boolean comments) {
super();
this.writer = writer;
this.pretty = pretty;
this.comments = pretty && comments;
}
@Override
public void comment(String content) {
if (comments) {
commentList.add(content);
}
}
@Override
public void beginObject() throws IOException {
checkState();
writer.write("{");
stepIn();
if (!valued.isEmpty()) {
valued.set(0, true);
}
valued.add(0, false);
}
private void commitComments() throws IOException {
if (comments) {
for (String s : commentList) {
writer.write("// ");
writer.write(s);
writer.write("\r\n");
for (int i = 0; i < indent; i++) {
writer.write(" ");
}
}
commentList.clear();
}
}
public void stepIn() throws IOException {
if (pretty) {
indent++;
writer.write("\r\n");
for (int i = 0; i < indent; i++) {
writer.write(" ");
}
}
}
public void stepOut() throws IOException {
if (pretty) {
indent--;
writer.write("\r\n");
for (int i = 0; i < indent; i++) {
writer.write(" ");
}
}
}
private void checkState() throws IOException {
commitComments();
if (named) {
if (pretty)
writer.write(" : ");
else
writer.write(":");
named = false;
}
if (!valued.isEmpty() && valued.get(0)) {
writer.write(",");
if (pretty) {
writer.write("\r\n");
for (int i = 0; i < indent; i++) {
writer.write(" ");
}
}
valued.set(0, false);
}
}
@Override
public void endObject() throws IOException {
stepOut();
writer.write("}");
valued.remove(0);
}
@Override
public void nullValue() throws IOException {
checkState();
writer.write("null");
valued.set(0, true);
}
@Override
public void name(String name) throws IOException {
checkState();
writer.write("\""+name+"\"");
named = true;
}
@Override
public void value(String value) throws IOException {
checkState();
writer.write("\""+Utilities.escapeJson(value)+"\"");
valued.set(0, true);
}
@Override
public void value(Boolean value) throws IOException {
checkState();
if (value == null)
writer.write("null");
else if (value.booleanValue())
writer.write("true");
else
writer.write("false");
valued.set(0, true);
}
@Override
public void value(BigDecimal value) throws IOException {
checkState();
if (value == null)
writer.write("null");
else
writer.write(value.toString());
valued.set(0, true);
}
@Override
public void valueNum(String value) throws IOException {
checkState();
if (value == null)
writer.write("null");
else
writer.write(value);
valued.set(0, true);
}
@Override
public void value(Integer value) throws IOException {
checkState();
if (value == null)
writer.write("null");
else
writer.write(value.toString());
valued.set(0, true);
}
@Override
public void beginArray() throws IOException {
checkState();
writer.write("[");
if (!valued.isEmpty()) {
valued.set(0, true);
}
valued.add(0, false);
}
@Override
public void endArray() throws IOException {
writer.write("]");
valued.remove(0);
}
@Override
public void finish() throws IOException {
writer.flush();
}
@Override
public void link(String href) {
// not used
}
@Override
public void anchor(String name) {
// not used
}
@Override
public void externalLink(String string) {
// not used
}
import java.io.IOException;
import java.io.Writer;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import org.hl7.fhir.utilities.Utilities;
/**
* A little implementation of a json write to replace Gson .... because Gson screws up decimal values, and *we care*
*
* @author Grahame Grieve
*
*/
public class JsonCreatorDirect implements JsonCreator {
private Writer writer;
private boolean pretty;
private boolean comments;
private boolean named;
private List<Boolean> valued = new ArrayList<Boolean>();
private int indent;
private List<String> commentList = new ArrayList<>();
public JsonCreatorDirect(Writer writer, boolean pretty, boolean comments) {
super();
this.writer = writer;
this.pretty = pretty;
this.comments = pretty && comments;
}
@Override
public void comment(String content) {
if (comments) {
commentList.add(content);
}
}
@Override
public void beginObject() throws IOException {
checkState();
writer.write("{");
stepIn();
if (!valued.isEmpty()) {
valued.set(0, true);
}
valued.add(0, false);
}
private void commitComments() throws IOException {
if (comments) {
for (String s : commentList) {
writer.write("// ");
writer.write(s);
writer.write("\r\n");
for (int i = 0; i < indent; i++) {
writer.write(" ");
}
}
commentList.clear();
}
}
public void stepIn() throws IOException {
if (pretty) {
indent++;
writer.write("\r\n");
for (int i = 0; i < indent; i++) {
writer.write(" ");
}
}
}
public void stepOut() throws IOException {
if (pretty) {
indent--;
writer.write("\r\n");
for (int i = 0; i < indent; i++) {
writer.write(" ");
}
}
}
private void checkState() throws IOException {
commitComments();
if (named) {
if (pretty)
writer.write(" : ");
else
writer.write(":");
named = false;
}
if (!valued.isEmpty() && valued.get(0)) {
writer.write(",");
if (pretty) {
writer.write("\r\n");
for (int i = 0; i < indent; i++) {
writer.write(" ");
}
}
valued.set(0, false);
}
}
@Override
public void endObject() throws IOException {
stepOut();
writer.write("}");
valued.remove(0);
}
@Override
public void nullValue() throws IOException {
checkState();
writer.write("null");
valued.set(0, true);
}
@Override
public void name(String name) throws IOException {
checkState();
writer.write("\""+name+"\"");
named = true;
}
@Override
public void value(String value) throws IOException {
checkState();
writer.write("\""+Utilities.escapeJson(value)+"\"");
valued.set(0, true);
}
@Override
public void value(Boolean value) throws IOException {
checkState();
if (value == null)
writer.write("null");
else if (value.booleanValue())
writer.write("true");
else
writer.write("false");
valued.set(0, true);
}
@Override
public void value(BigDecimal value) throws IOException {
checkState();
if (value == null)
writer.write("null");
else
writer.write(value.toString());
valued.set(0, true);
}
@Override
public void valueNum(String value) throws IOException {
checkState();
if (value == null)
writer.write("null");
else
writer.write(value);
valued.set(0, true);
}
@Override
public void value(Integer value) throws IOException {
checkState();
if (value == null)
writer.write("null");
else
writer.write(value.toString());
valued.set(0, true);
}
@Override
public void beginArray() throws IOException {
checkState();
writer.write("[");
if (!valued.isEmpty()) {
valued.set(0, true);
}
valued.add(0, false);
}
@Override
public void endArray() throws IOException {
writer.write("]");
valued.remove(0);
}
@Override
public void finish() throws IOException {
writer.flush();
}
@Override
public void link(String href) {
// not used
}
@Override
public void anchor(String name) {
// not used
}
@Override
public void externalLink(String string) {
// not used
}
@Override
public boolean canElide() { return false; }
@Override
public void elide() {
// not used
}
}

View File

@ -1,5 +1,5 @@
package org.hl7.fhir.r5.formats;
package org.hl7.fhir.r5.formats;
/*
Copyright (c) 2011+, HL7, Inc.
All rights reserved.
@ -28,103 +28,111 @@ package org.hl7.fhir.r5.formats;
POSSIBILITY OF SUCH DAMAGE.
*/
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.math.BigDecimal;
import com.google.gson.stream.JsonWriter;
public class JsonCreatorGson implements JsonCreator {
JsonWriter gson;
public JsonCreatorGson(OutputStreamWriter osw) {
gson = new JsonWriter(osw);
}
@Override
public void beginObject() throws IOException {
gson.beginObject();
}
@Override
public void endObject() throws IOException {
gson.endObject();
}
@Override
public void nullValue() throws IOException {
gson.nullValue();
}
@Override
public void name(String name) throws IOException {
gson.name(name);
}
@Override
public void value(String value) throws IOException {
gson.value(value);
}
@Override
public void value(Boolean value) throws IOException {
gson.value(value);
}
@Override
public void value(BigDecimal value) throws IOException {
gson.value(value);
}
@Override
public void value(Integer value) throws IOException {
gson.value(value);
}
@Override
public void beginArray() throws IOException {
gson.beginArray();
}
@Override
public void endArray() throws IOException {
gson.endArray();
}
@Override
public void finish() {
// nothing to do here
}
@Override
public void link(String href) {
// not used
}
@Override
public void valueNum(String value) throws IOException {
value(new BigDecimal(value));
}
@Override
public void anchor(String name) {
// not used
}
@Override
public void comment(String content) {
// gson (dense json) ignores comments
}
@Override
public void externalLink(String string) {
// not used
}
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.math.BigDecimal;
import com.google.gson.stream.JsonWriter;
public class JsonCreatorGson implements JsonCreator {
JsonWriter gson;
public JsonCreatorGson(OutputStreamWriter osw) {
gson = new JsonWriter(osw);
}
@Override
public void beginObject() throws IOException {
gson.beginObject();
}
@Override
public void endObject() throws IOException {
gson.endObject();
}
@Override
public void nullValue() throws IOException {
gson.nullValue();
}
@Override
public void name(String name) throws IOException {
gson.name(name);
}
@Override
public void value(String value) throws IOException {
gson.value(value);
}
@Override
public void value(Boolean value) throws IOException {
gson.value(value);
}
@Override
public void value(BigDecimal value) throws IOException {
gson.value(value);
}
@Override
public void value(Integer value) throws IOException {
gson.value(value);
}
@Override
public void beginArray() throws IOException {
gson.beginArray();
}
@Override
public void endArray() throws IOException {
gson.endArray();
}
@Override
public void finish() {
// nothing to do here
}
@Override
public void link(String href) {
// not used
}
@Override
public void valueNum(String value) throws IOException {
value(new BigDecimal(value));
}
@Override
public void anchor(String name) {
// not used
}
@Override
public void comment(String content) {
// gson (dense json) ignores comments
}
@Override
public void externalLink(String string) {
// not used
}
@Override
public void elide() {
// not used
}
@Override
public boolean canElide() { return false;}
}

View File

@ -36,7 +36,7 @@ public class AdditionalBindingsRenderer {
private String valueSet;
private String doco;
private String docoShort;
private UsageContext usage;
private List<UsageContext> usages = new ArrayList<UsageContext>();
private boolean any = false;
private boolean isUnchanged = false;
private boolean matched = false;
@ -72,7 +72,7 @@ public class AdditionalBindingsRenderer {
isUnchanged = isUnchanged && ((valueSet==null && compare.valueSet==null) || valueSet.equals(compare.valueSet));
isUnchanged = isUnchanged && ((doco==null && compare.doco==null) || doco.equals(compare.doco));
isUnchanged = isUnchanged && ((docoShort==null && compare.docoShort==null) || docoShort.equals(compare.docoShort));
isUnchanged = isUnchanged && ((usage==null && compare.usage==null) || usage.equals(compare.usage));
isUnchanged = isUnchanged && ((usages==null && compare.usages==null) || usages.equals(compare.usages));
return isUnchanged;
}
}
@ -174,8 +174,12 @@ public class AdditionalBindingsRenderer {
abr.purpose = ext.getExtensionString("purpose");
abr.valueSet = ext.getExtensionString("valueSet");
abr.doco = ext.getExtensionString("documentation");
abr.docoShort = ext.getExtensionString("shortDoco");
abr.usage = (ext.hasExtension("usage")) && ext.getExtensionByUrl("usage").hasValueUsageContext() ? ext.getExtensionByUrl("usage").getValueUsageContext() : null;
abr.docoShort = ext.getExtensionString("shortDoco");
for (Extension x : ext.getExtensionsByUrl("usage")) {
if (x.hasValueUsageContext()) {
abr.usages.add(x.getValueUsageContext());
}
}
abr.any = "any".equals(ext.getExtensionString("scope"));
abr.isUnchanged = ext.hasUserData(ProfileUtilities.UD_DERIVATION_EQUALS);
return abr;
@ -187,7 +191,7 @@ public class AdditionalBindingsRenderer {
abr.valueSet = ab.getValueSet();
abr.doco = ab.getDocumentation();
abr.docoShort = ab.getShortDoco();
abr.usage = ab.hasUsage() ? ab.getUsageFirstRep() : null;
abr.usages.addAll(ab.getUsage());
abr.any = ab.getAny();
abr.isUnchanged = ab.hasUserData(ProfileUtilities.UD_DERIVATION_EQUALS);
return abr;
@ -220,7 +224,7 @@ public class AdditionalBindingsRenderer {
boolean any = false;
for (AdditionalBindingDetail binding : bindings) {
doco = doco || binding.getDoco(fullDoco)!=null || (binding.compare!=null && binding.compare.getDoco(fullDoco)!=null);
usage = usage || binding.usage != null || (binding.compare!=null && binding.compare.usage!=null);
usage = usage || !binding.usages.isEmpty() || (binding.compare!=null && !binding.compare.usages.isEmpty());
any = any || binding.any || (binding.compare!=null && binding.compare.any);
}
@ -283,9 +287,12 @@ public class AdditionalBindingsRenderer {
renderPurpose(purpose, binding.compare.purpose);
}
if (usage) {
if (binding.usage != null) {
// TODO: This isn't rendered at all yet. Ideally, we want it to render with comparison...
new DataRenderer(context).renderBase(new RenderingStatus(), tr.td(), binding.usage);
if (!binding.usages.isEmpty()) {
XhtmlNode td = tr.td();
for (UsageContext uc : binding.usages) {
td.sep(", ");
new DataRenderer(context).renderBase(new RenderingStatus(), td, uc);
}
} else {
tr.td();
}

View File

@ -46,6 +46,7 @@ import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules;
import org.hl7.fhir.r5.renderers.utils.RenderingContext.ResourceRendererMode;
import org.hl7.fhir.r5.renderers.utils.ResourceWrapper;
import org.hl7.fhir.r5.terminologies.JurisdictionUtilities;
import org.hl7.fhir.r5.terminologies.utilities.SnomedUtilities;
import org.hl7.fhir.r5.terminologies.utilities.ValidationResult;
import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
@ -1177,8 +1178,8 @@ public class DataRenderer extends Renderer implements CodeResolver {
}
private String getLinkForSystem(String system, String version) {
if ("http://snomed.info/sct".equals(system)) {
return "https://browser.ihtsdotools.org/";
if ("http://snomed.info/sct".equals(system)) {
return "https://browser.ihtsdotools.org/";
} else if ("http://loinc.org".equals(system)) {
return "https://loinc.org/";
} else if ("http://unitsofmeasure.org".equals(system)) {
@ -1198,11 +1199,7 @@ public class DataRenderer extends Renderer implements CodeResolver {
protected String getLinkForCode(String system, String version, String code) {
if ("http://snomed.info/sct".equals(system)) {
if (!Utilities.noString(code)) {
return "http://snomed.info/id/"+code;
} else {
return "https://browser.ihtsdotools.org/";
}
return SnomedUtilities.getSctLink(version, code, context.getContext().getExpansionParameters());
} else if ("http://loinc.org".equals(system)) {
if (!Utilities.noString(code)) {
return "https://loinc.org/"+code;
@ -1301,7 +1298,11 @@ public class DataRenderer extends Renderer implements CodeResolver {
}
}
protected void renderCoding(RenderingStatus status, XhtmlNode x, ResourceWrapper c) {
protected void renderCoding(RenderingStatus status, XhtmlNode x, ResourceWrapper c) {
renderCoding(status, x, c, true);
}
protected void renderCoding(RenderingStatus status, XhtmlNode x, ResourceWrapper c, boolean details) {
String s = "";
if (c.has("display"))
s = context.getTranslated(c.child("display"));
@ -1311,10 +1312,13 @@ public class DataRenderer extends Renderer implements CodeResolver {
if (Utilities.noString(s))
s = c.primitiveValue("code");
if (context.isTechnicalMode()) {
x.addText(s+" "+context.formatPhrase(RenderingContext.DATA_REND_DETAILS_STATED, displaySystem(c.primitiveValue("system")), c.primitiveValue("code"), " = '", lookupCode(c.primitiveValue("system"), c.primitiveValue("version"), c.primitiveValue("code")), c.primitiveValue("display"), "')"));
} else
x.span(null, "{"+c.primitiveValue("system")+" "+c.primitiveValue("code")+"}").addText(s);
if (context.isTechnicalMode() && details) {
String d = c.primitiveValue("display") == null ? lookupCode(c.primitiveValue("system"), c.primitiveValue("version"), c.primitiveValue("code")): c.primitiveValue("display");
d = context.formatPhrase(d == null || d.equals(c.primitiveValue("code")) ? RenderingContext.DATA_REND_DETAILS_STATED_ND : RenderingContext.DATA_REND_DETAILS_STATED, displaySystem(c.primitiveValue("system")), c.primitiveValue("code"), d);
x.addText(s+" "+d);
} else {
x.span(null, "{"+c.primitiveValue("system")+" "+c.primitiveValue("code")+"}").addText(s);
}
}
public String displayCodeableConcept(ResourceWrapper cc) {
@ -1860,8 +1864,8 @@ public class DataRenderer extends Renderer implements CodeResolver {
}
public void renderUsageContext(RenderingStatus status, XhtmlNode x, ResourceWrapper u) throws FHIRFormatError, DefinitionException, IOException {
renderCoding(status, x, u.child("code"));
x.tx(": ");
renderCoding(status, x, u.child("code"), false);
x.tx(" = ");
renderDataType(status, x, u.child("value"));
}

View File

@ -51,6 +51,7 @@ import org.hl7.fhir.r5.terminologies.CodeSystemUtilities;
import org.hl7.fhir.r5.terminologies.ValueSetUtilities;
import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpansionOutcome;
import org.hl7.fhir.r5.terminologies.utilities.CodingValidationRequest;
import org.hl7.fhir.r5.terminologies.utilities.SnomedUtilities;
import org.hl7.fhir.r5.terminologies.utilities.ValidationResult;
import org.hl7.fhir.r5.utils.EOperationOutcome;
import org.hl7.fhir.r5.utils.ToolingExtensions;
@ -825,7 +826,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
}
String s = Utilities.padLeft("", '\u00A0', i*2);
td.attribute("style", "white-space:nowrap").addText(s);
addCodeToTable(c.getAbstract(), c.getSystem(), c.getCode(), c.getDisplay(), td);
addCodeToTable(c.getAbstract(), c.getSystem(), c.getVersion(), c.getCode(), c.getDisplay(), td);
td = tr.td();
td.addText(c.getSystem());
td = tr.td();
@ -863,7 +864,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
first = false;
XhtmlNode span = td.span(null, mapping.comp.getRelationship().toString());
span.addText(getCharForRelationship(mapping.comp));
addRefToCode(td, mapping.group.getTarget(), m.getLink(), mapping.comp.getCode());
addRefToCode(td, mapping.group.getTarget(), null, m.getLink(), mapping.comp.getCode());
if (!Utilities.noString(mapping.comp.getComment()))
td.i().tx("("+mapping.comp.getComment()+")");
}
@ -900,13 +901,13 @@ public class ValueSetRenderer extends TerminologyRenderer {
return true;
}
private void addCodeToTable(boolean isAbstract, String system, String code, String display, XhtmlNode td) {
private void addCodeToTable(boolean isAbstract, String system, String version, String code, String display, XhtmlNode td) {
CodeSystem e = getContext().getWorker().fetchCodeSystem(system);
if (e == null || (e.getContent() != org.hl7.fhir.r5.model.Enumerations.CodeSystemContentMode.COMPLETE && e.getContent() != org.hl7.fhir.r5.model.Enumerations.CodeSystemContentMode.FRAGMENT)) {
if (isAbstract)
td.i().setAttribute("title", context.formatPhrase(RenderingContext.VS_ABSTRACT_CODE_HINT)).addText(code);
else if ("http://snomed.info/sct".equals(system)) {
td.ah(context.prefixLocalHref(sctLink(code))).addText(code);
td.ah(context.prefixLocalHref(SnomedUtilities.getSctLink(version, code, context.getContext().getExpansionParameters()))).addText(code);
} else if ("http://loinc.org".equals(system)) {
td.ah(context.prefixLocalHref(LoincLinker.getLinkForCode(code))).addText(code);
} else
@ -928,15 +929,8 @@ public class ValueSetRenderer extends TerminologyRenderer {
}
}
public String sctLink(String code) {
// if (snomedEdition != null)
// http://browser.ihtsdotools.org/?perspective=full&conceptId1=428041000124106&edition=us-edition&release=v20180301&server=https://prod-browser-exten.ihtsdotools.org/api/snomed&langRefset=900000000000509007
return "http://snomed.info/id/"+code;
}
private void addRefToCode(XhtmlNode td, String target, String vslink, String code) {
addCodeToTable(false, target, code, null, td);
private void addRefToCode(XhtmlNode td, String target, String vslink, String code, String version) {
addCodeToTable(false, target, version, code, null, td);
// CodeSystem cs = getContext().getWorker().fetchCodeSystem(target);
// String cslink = getCsRef(cs);
// String link = cslink != null ? cslink+"#"+cs.getId()+"-"+code : vslink+"#"+code;
@ -1212,10 +1206,10 @@ public class ValueSetRenderer extends TerminologyRenderer {
}
addMapHeaders(addTableHeaderRowStandard(t, false, true, hasDefinition, hasComments, false, false, null, langs, designations, doDesignations), maps);
for (ConceptReferenceComponent c : inc.getConcept()) {
renderConcept(inc, langs, doDesignations, maps, designations, definitions, t, hasComments, hasDefinition, c);
renderConcept(inc, langs, doDesignations, maps, designations, definitions, t, hasComments, hasDefinition, c, inc.getVersion());
}
for (Base b : VersionComparisonAnnotation.getDeleted(inc, "concept" )) {
renderConcept(inc, langs, doDesignations, maps, designations, definitions, t, hasComments, hasDefinition, (ConceptReferenceComponent) b);
renderConcept(inc, langs, doDesignations, maps, designations, definitions, t, hasComments, hasDefinition, (ConceptReferenceComponent) b, inc.getVersion());
}
}
if (inc.getFilter().size() > 0) {
@ -1312,11 +1306,11 @@ public class ValueSetRenderer extends TerminologyRenderer {
private void renderConcept(ConceptSetComponent inc, List<String> langs, boolean doDesignations,
List<UsedConceptMap> maps, Map<String, String> designations, Map<String, ConceptDefinitionComponent> definitions,
XhtmlNode t, boolean hasComments, boolean hasDefinition, ConceptReferenceComponent c) {
XhtmlNode t, boolean hasComments, boolean hasDefinition, ConceptReferenceComponent c, String version) {
XhtmlNode tr = t.tr();
XhtmlNode td = renderStatusRow(c, t, tr);
ConceptDefinitionComponent cc = definitions == null ? null : definitions.get(c.getCode());
addCodeToTable(false, inc.getSystem(), c.getCode(), c.hasDisplay()? c.getDisplay() : cc != null ? cc.getDisplay() : "", td);
addCodeToTable(false, inc.getSystem(), version, c.getCode(), c.hasDisplay()? c.getDisplay() : cc != null ? cc.getDisplay() : "", td);
td = tr.td();
if (!Utilities.noString(c.getDisplay()))
@ -1355,7 +1349,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
first = false;
XhtmlNode span = td.span(null, mapping.comp.getRelationship().toString());
span.addText(getCharForRelationship(mapping.comp));
addRefToCode(td, mapping.group.getTarget(), m.getLink(), mapping.comp.getCode());
addRefToCode(td, mapping.group.getTarget(), m.getLink(), mapping.comp.getCode(), version);
if (!Utilities.noString(mapping.comp.getComment()))
td.i().tx("("+mapping.comp.getComment()+")");
}

View File

@ -51,6 +51,8 @@ public class TerminologyClientContext {
}
private static boolean canUseCacheId;
private ITerminologyClient client;
private boolean initialised = false;
private CapabilityStatement capabilitiesStatementQuick;
@ -180,7 +182,7 @@ public class TerminologyClientContext {
txCache.cacheTerminologyCapabilities(getAddress(), txcaps);
}
}
if (txcaps != null) {
if (txcaps != null && TerminologyClientContext.canUseCacheId) {
for (TerminologyCapabilitiesExpansionParameterComponent t : txcaps.getExpansion().getParameter()) {
if ("cache-id".equals(t.getName())) {
setTxCaching(true);
@ -206,6 +208,13 @@ public class TerminologyClientContext {
public String toString() {
return client.getAddress();
}
public static boolean isCanUseCacheId() {
return canUseCacheId;
}
public static void setCanUseCacheId(boolean canUseCacheId) {
TerminologyClientContext.canUseCacheId = canUseCacheId;
}
}

View File

@ -188,7 +188,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
private ValueSetExpansionContainsComponent addCode(WorkingContext wc, String system, String code, String display, String dispLang, ValueSetExpansionContainsComponent parent, List<ConceptDefinitionDesignationComponent> designations, Parameters expParams,
boolean isAbstract, boolean inactive, List<ValueSet> filters, boolean noInactive, boolean deprecated, List<ValueSetExpansionPropertyComponent> vsProp,
List<ConceptPropertyComponent> csProps, CodeSystem cs, List<org.hl7.fhir.r5.model.ValueSet.ConceptPropertyComponent> expProps, List<Extension> csExtList, List<Extension> vsExtList, ValueSetExpansionComponent exp) throws ETooCostly {
opContext.deadCheck();
opContext.deadCheck("addCode"+code);
if (filters != null && !filters.isEmpty() && !filterContainsCode(filters, system, code, exp))
return null;
@ -447,7 +447,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
}
private void addCodeAndDescendents(WorkingContext wc, ValueSetExpansionContainsComponent focus, ValueSetExpansionContainsComponent parent, Parameters expParams, List<ValueSet> filters, boolean noInactive, List<ValueSetExpansionPropertyComponent> vsProps, ValueSet vsSrc, ValueSetExpansionComponent exp) throws FHIRException, ETooCostly {
opContext.deadCheck();
opContext.deadCheck("addCodeAndDescendents");
focus.checkNoModifiers("Expansion.contains", "expanding");
ValueSetExpansionContainsComponent np = null;
for (String code : getCodesForConcept(focus, expParams)) {
@ -497,7 +497,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
private void addCodeAndDescendents(WorkingContext wc, CodeSystem cs, String system, ConceptDefinitionComponent def, ValueSetExpansionContainsComponent parent, Parameters expParams, List<ValueSet> filters,
ConceptDefinitionComponent exclusion, ConceptFilter filterFunc, boolean noInactive, List<ValueSetExpansionPropertyComponent> vsProps, List<WorkingContext> otherFilters, ValueSetExpansionComponent exp) throws FHIRException, ETooCostly {
opContext.deadCheck();
opContext.deadCheck("addCodeAndDescendents");
def.checkNoModifiers("Code in Code System", "expanding");
if (exclusion != null) {
if (exclusion.getCode().equals(def.getCode()))
@ -528,7 +528,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
private void excludeCodeAndDescendents(WorkingContext wc, CodeSystem cs, String system, ConceptDefinitionComponent def, Parameters expParams, List<ValueSet> filters,
ConceptDefinitionComponent exclusion, ConceptFilter filterFunc, List<WorkingContext> otherFilters, ValueSetExpansionComponent exp) throws FHIRException, ETooCostly {
opContext.deadCheck();
opContext.deadCheck("excludeCodeAndDescendents");
def.checkNoModifiers("Code in Code System", "expanding");
if (exclusion != null) {
if (exclusion.getCode().equals(def.getCode()))
@ -596,7 +596,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
}
private void excludeCodes(WorkingContext wc, ConceptSetComponent exc, Parameters expParams, ValueSetExpansionComponent exp, ValueSet vs) throws FHIRException, FileNotFoundException, ETooCostly, IOException {
opContext.deadCheck();
opContext.deadCheck("excludeCodes");
exc.checkNoModifiers("Compose.exclude", "expanding");
if (exc.hasSystem() && exc.getConcept().size() == 0 && exc.getFilter().size() == 0) {
wc.getExcludeSystems().add(exc.getSystem());
@ -639,7 +639,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
}
private void excludeCodes(WorkingContext wc, ValueSetExpansionComponent expand) {
opContext.deadCheck();
opContext.deadCheck("excludeCodes");
for (ValueSetExpansionContainsComponent c : expand.getContains()) {
excludeCode(wc, c.getSystem(), c.getCode());
}
@ -959,7 +959,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
}
public void copyExpansion(WorkingContext wc,List<ValueSetExpansionContainsComponent> list) {
opContext.deadCheck();
opContext.deadCheck("copyExpansion");
for (ValueSetExpansionContainsComponent cc : list) {
ValueSetExpansionContainsComponent n = new ValueSet.ValueSetExpansionContainsComponent();
n.setSystem(cc.getSystem());
@ -988,7 +988,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
private int copyImportContains(List<ValueSetExpansionContainsComponent> list, ValueSetExpansionContainsComponent parent, Parameters expParams, List<ValueSet> filter, boolean noInactive, List<ValueSetExpansionPropertyComponent> vsProps, ValueSet vsSrc, ValueSetExpansionComponent exp) throws FHIRException, ETooCostly {
int count = 0;
opContext.deadCheck();
opContext.deadCheck("copyImportContains");
for (ValueSetExpansionContainsComponent c : list) {
c.checkNoModifiers("Imported Expansion in Code System", "expanding");
ValueSetExpansionContainsComponent np = addCode(dwc, c.getSystem(), c.getCode(), c.getDisplay(), vsSrc.getLanguage(), parent, null, expParams, c.getAbstract(), c.getInactive(),
@ -1002,7 +1002,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
}
private void includeCodes(ConceptSetComponent inc, ValueSetExpansionComponent exp, Parameters expParams, boolean heirarchical, boolean noInactive, List<Extension> extensions, ValueSet valueSet) throws ETooCostly, FileNotFoundException, IOException, FHIRException, CodeSystemProviderExtension {
opContext.deadCheck();
opContext.deadCheck("includeCodes");
inc.checkNoModifiers("Compose.include", "expanding");
List<ValueSet> imports = new ArrayList<ValueSet>();
for (CanonicalType imp : inc.getValueSet()) {
@ -1033,7 +1033,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
}
private void doServerIncludeCodes(ConceptSetComponent inc, boolean heirarchical, ValueSetExpansionComponent exp, List<ValueSet> imports, Parameters expParams, List<Extension> extensions, boolean noInactive, List<ValueSetExpansionPropertyComponent> vsProps) throws FHIRException, CodeSystemProviderExtension, ETooCostly {
opContext.deadCheck();
opContext.deadCheck("doServerIncludeCodes");
CodeSystemProvider csp = CodeSystemProvider.factory(inc.getSystem());
if (csp != null) {
csp.includeCodes(inc, heirarchical, exp, imports, expParams, extensions, noInactive, vsProps);
@ -1075,7 +1075,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
public void doInternalIncludeCodes(ConceptSetComponent inc, ValueSetExpansionComponent exp, Parameters expParams, List<ValueSet> imports, CodeSystem cs, boolean noInactive, Resource vsSrc) throws NoTerminologyServiceException, TerminologyServiceException, FHIRException, ETooCostly {
opContext.deadCheck();
opContext.deadCheck("doInternalIncludeCodes");
if (cs == null) {
if (context.isNoTerminologyServer())
throw failTSE("Unable to find code system " + inc.getSystem().toString());
@ -1160,7 +1160,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
private void processFilter(ConceptSetComponent inc, ValueSetExpansionComponent exp, Parameters expParams, List<ValueSet> imports, CodeSystem cs, boolean noInactive,
ConceptSetFilterComponent fc, WorkingContext wc, List<WorkingContext> filters, boolean exclude)
throws ETooCostly {
opContext.deadCheck();
opContext.deadCheck("processFilter");
if ("concept".equals(fc.getProperty()) && fc.getOp() == FilterOperator.ISA) {
// special: all codes in the target code system under the value
ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), fc.getValue());
@ -1213,7 +1213,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
if (isNotBlank(def.getDisplay()) && isNotBlank(fc.getValue())) {
if (def.getDisplay().contains(fc.getValue()) && passesOtherFilters(filters, cs, def.getCode())) {
for (String code : getCodesForConcept(def, expParams)) {
opContext.deadCheck();
opContext.deadCheck("processFilter2");
if (exclude) {
excludeCode(wc, inc.getSystem(), code);
} else {

View File

@ -0,0 +1,74 @@
package org.hl7.fhir.r5.terminologies.utilities;
import org.hl7.fhir.r5.model.Parameters;
import org.hl7.fhir.r5.model.Parameters.ParametersParameterComponent;
import org.hl7.fhir.utilities.Utilities;
//URL: http://snomed.info/sct/[module]/version/[e.g. 20150131]'
//International: 900000000000207008
//US: 731000124108
//Australia: 32506021000036107
//Belgium: 11000172109
//Canada: 20611000087101
//Spain: 449081005
//Denmark: 554471000005108
//Netherlands: 11000146104
//Sweden: 45991000052106
//Switzerland: 2011000195101
//UK: 83821000000107
//IPS: 827022005
public class SnomedUtilities {
public static String getVersionFromParameters(Parameters p, String version) {
for (ParametersParameterComponent pp : p.getParameter()) {
switch (pp.getName()) {
case "system-version" :
if (version == null) {
return pp.getValue().primitiveValue();
}
case "force-system-version":
return pp.getValue().primitiveValue();
}
}
return version;
}
public static String getEditionFromVersion(String version) {
if (version == null) {
return null;
}
if (version.startsWith("http://snomed.info/sct/")) {
version = version.substring(23);
}
if (version.contains("/")) {
version = version.substring(0, version.indexOf("/"));
}
if (Utilities.existsInList(version, "900000000000207008", "731000124108", "32506021000036107", "11000172109", "20611000087101",
"449081005", "554471000005108", "11000146104", "45991000052106", "2011000195101", "83821000000107", "827022005")) {
return version;
} else {
return null;
}
}
public static String getSctLink(String version, String code, Parameters p) {
if (!Utilities.noString(code)) {
version = SnomedUtilities.getVersionFromParameters(p, version);
String edId = SnomedUtilities.getEditionFromVersion(version);
if (edId != null) {
// if there's a version that's an edition, then:
// http://snomed.info/sct/11000172109/id//371305003
return "http://snomed.info/sct/"+edId+"/id/"+code;
} else {
// no, version:
return "http://snomed.info/id/"+code;
}
} else {
return "https://browser.ihtsdotools.org/";
}
}
}

View File

@ -302,22 +302,26 @@ public class TerminologyCache {
this.lock = lock;
if (folder == null) {
folder = Utilities.path("[tmp]", "default-tx-cache");
} else if ("n/a".equals(folder)) {
// this is a weird way to do things but it maintains the legacy interface
folder = null;
}
this.folder = folder;
requestCount = 0;
hitCount = 0;
networkCount = 0;
File f = ManagedFileAccess.file(folder);
if (!f.exists()) {
Utilities.createDirectory(folder);
if (folder != null) {
File f = ManagedFileAccess.file(folder);
if (!f.exists()) {
Utilities.createDirectory(folder);
}
if (!f.exists()) {
throw new IOException("Unable to create terminology cache at "+folder);
}
checkVersion();
load();
}
if (!f.exists()) {
throw new IOException("Unable to create terminology cache at "+folder);
}
checkVersion();
load();
}
private void checkVersion() throws IOException {
@ -361,7 +365,9 @@ public class TerminologyCache {
}
private void clear() throws IOException {
Utilities.clearDirectory(folder);
if (folder != null) {
Utilities.clearDirectory(folder);
}
caches.clear();
vsCache.clear();
csCache.clear();
@ -1039,7 +1045,7 @@ public class TerminologyCache {
public SourcedValueSet getValueSet(String canonical) {
SourcedValueSetEntry sp = vsCache.get(canonical);
if (sp == null) {
if (sp == null || folder == null) {
return null;
} else {
try {
@ -1052,7 +1058,7 @@ public class TerminologyCache {
public SourcedCodeSystem getCodeSystem(String canonical) {
SourcedCodeSystemEntry sp = csCache.get(canonical);
if (sp == null) {
if (sp == null || folder == null) {
return null;
} else {
try {
@ -1073,7 +1079,9 @@ public class TerminologyCache {
} else {
String uuid = Utilities.makeUuidLC();
String fn = "vs-"+uuid+".json";
new JsonParser().compose(ManagedFileAccess.outStream(Utilities.path(folder, fn)), svs.getVs());
if (folder != null) {
new JsonParser().compose(ManagedFileAccess.outStream(Utilities.path(folder, fn)), svs.getVs());
}
vsCache.put(canonical, new SourcedValueSetEntry(svs.getServer(), fn));
}
org.hl7.fhir.utilities.json.model.JsonObject j = new org.hl7.fhir.utilities.json.model.JsonObject();
@ -1090,7 +1098,9 @@ public class TerminologyCache {
j.add(k, e);
}
}
org.hl7.fhir.utilities.json.parser.JsonParser.compose(j, ManagedFileAccess.file(Utilities.path(folder, "vs-externals.json")), true);
if (folder != null) {
org.hl7.fhir.utilities.json.parser.JsonParser.compose(j, ManagedFileAccess.file(Utilities.path(folder, "vs-externals.json")), true);
}
} catch (Exception e) {
e.printStackTrace();
}
@ -1106,7 +1116,9 @@ public class TerminologyCache {
} else {
String uuid = Utilities.makeUuidLC();
String fn = "cs-"+uuid+".json";
new JsonParser().compose(ManagedFileAccess.outStream(Utilities.path(folder, fn)), scs.getCs());
if (folder != null) {
new JsonParser().compose(ManagedFileAccess.outStream(Utilities.path(folder, fn)), scs.getCs());
}
csCache.put(canonical, new SourcedCodeSystemEntry(scs.getServer(), fn));
}
org.hl7.fhir.utilities.json.model.JsonObject j = new org.hl7.fhir.utilities.json.model.JsonObject();
@ -1123,7 +1135,9 @@ public class TerminologyCache {
j.add(k, e);
}
}
org.hl7.fhir.utilities.json.parser.JsonParser.compose(j, ManagedFileAccess.file(Utilities.path(folder, "cs-externals.json")), true);
if (folder != null) {
org.hl7.fhir.utilities.json.parser.JsonParser.compose(j, ManagedFileAccess.file(Utilities.path(folder, "cs-externals.json")), true);
}
} catch (Exception e) {
e.printStackTrace();
}

View File

@ -7,6 +7,7 @@ import org.hl7.fhir.exceptions.TerminologyServiceException;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.OperationOutcome.IssueType;
import org.hl7.fhir.r5.terminologies.utilities.TerminologyOperationContext.TerminologyServiceProtectionException;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.i18n.I18nConstants;
import org.hl7.fhir.utilities.validation.ValidationOptions;
@ -38,16 +39,22 @@ public class TerminologyOperationContext {
public static boolean debugging = java.lang.management.ManagementFactory.getRuntimeMXBean().getInputArguments().toString().indexOf("-agentlib:jdwp") > 0;
private static final int EXPANSION_DEAD_TIME_SECS = 60;
private long deadTime;
private int nestCount = 0;
private long startTime;
private List<String> contexts = new ArrayList<>();
private IWorkerContext worker;
private boolean original;
private ValidationOptions options;
private String name;
private List<String> notes = new ArrayList<>();
public TerminologyOperationContext(IWorkerContext worker, ValidationOptions options) {
public TerminologyOperationContext(IWorkerContext worker, ValidationOptions options, String name) {
super();
this.worker = worker;
this.original = true;
this.options = options;
this.name = name;
this.startTime = System.currentTimeMillis();
if (EXPANSION_DEAD_TIME_SECS == 0 || debugging) {
deadTime = 0;
@ -56,22 +63,33 @@ public class TerminologyOperationContext {
}
}
private TerminologyOperationContext(ValidationOptions options) {
private TerminologyOperationContext(ValidationOptions options, String name) {
super();
this.options = options;
this.name = name;
this.startTime = System.currentTimeMillis();
}
public TerminologyOperationContext copy() {
TerminologyOperationContext ret = new TerminologyOperationContext(this.options);
TerminologyOperationContext ret = new TerminologyOperationContext(this.options, name);
ret.worker = worker;
ret.contexts.addAll(contexts);
ret.deadTime = deadTime;
ret.notes = notes;
ret.startTime = startTime;
ret.nestCount = nestCount + 1;
return ret;
}
public void deadCheck() {
public void deadCheck(String note) {
note(note);
if (deadTime != 0 && System.currentTimeMillis() > deadTime) {
throw new TerminologyServiceProtectionException(worker.formatMessage(I18nConstants.VALUESET_TOO_COSTLY_TIME, contexts.get(0), EXPANSION_DEAD_TIME_SECS), TerminologyServiceErrorClass.TOO_COSTLY, IssueType.TOOCOSTLY);
System.out.println();
System.out.println("Operation took too long - longer than "+(deadTime - startTime)+"ms");
for (String s : notes) {
System.out.println(s);
}
throw new TerminologyServiceProtectionException(worker.formatMessage(I18nConstants.VALUESET_TOO_COSTLY_TIME, contexts.get(0), EXPANSION_DEAD_TIME_SECS, name+" (local)"), TerminologyServiceErrorClass.TOO_COSTLY, IssueType.TOOCOSTLY);
}
}
@ -90,5 +108,8 @@ public class TerminologyOperationContext {
return options;
}
public void note(String s) {
s = Utilities.padLeft("", ' ', nestCount)+" "+(System.currentTimeMillis() - startTime)+" "+s;
notes.add(s);
}
}

View File

@ -49,7 +49,7 @@ public class ValueSetProcessBase {
protected IWorkerContext context;
protected TerminologyOperationContext opContext;
protected List<String> requiredSupplements = new ArrayList<>();
protected ValueSetProcessBase(IWorkerContext context, TerminologyOperationContext opContext) {
super();
this.context = context;
@ -229,7 +229,11 @@ public class ValueSetProcessBase {
}
}
}
public TerminologyOperationContext getOpContext() {
return opContext;
}
protected AlternateCodesProcessingRules altCodeParams = new AlternateCodesProcessingRules(false);
protected AlternateCodesProcessingRules allAltCodes = new AlternateCodesProcessingRules(true);

View File

@ -175,11 +175,15 @@ public class ValueSetValidator extends ValueSetProcessBase {
}
private void analyseValueSet() {
opContext.note("analyse");
if (valueset != null) {
opContext.note("vs = "+valueset.getVersionedUrl());
opContext.seeContext(valueset.getVersionedUrl());
for (Extension s : valueset.getExtensionsByUrl(ExtensionConstants.EXT_VSSUPPLEMENT)) {
requiredSupplements.add(s.getValue().primitiveValue());
}
} else {
opContext.note("vs = null");
}
altCodeParams.seeParameters(expansionProfile);
@ -187,17 +191,18 @@ public class ValueSetValidator extends ValueSetProcessBase {
if (localContext != null) {
if (valueset != null) {
for (ConceptSetComponent i : valueset.getCompose().getInclude()) {
analyseComponent(i);
analyseComponent(i, "inc"+i);
}
for (ConceptSetComponent i : valueset.getCompose().getExclude()) {
analyseComponent(i);
analyseComponent(i, "exc"+i);
}
}
}
opContext.note("analysed");
}
private void analyseComponent(ConceptSetComponent i) {
opContext.deadCheck();
private void analyseComponent(ConceptSetComponent i, String name) {
opContext.deadCheck("analyse Component "+name);
if (i.getSystemElement().hasExtension(ToolingExtensions.EXT_VALUESET_SYSTEM)) {
String ref = i.getSystemElement().getExtensionString(ToolingExtensions.EXT_VALUESET_SYSTEM);
if (ref.startsWith("#")) {
@ -219,11 +224,15 @@ public class ValueSetValidator extends ValueSetProcessBase {
}
public ValidationResult validateCode(String path, CodeableConcept code) throws FHIRException {
opContext.deadCheck();
opContext.deadCheck("validate "+code.toString());
checkValueSetOptions();
// first, we validate the codings themselves
ValidationProcessInfo info = new ValidationProcessInfo();
if (throwToServer) {
checkValueSetLoad(info);
}
CodeableConcept vcc = new CodeableConcept();
List<ValidationResult> resList = new ArrayList<>();
@ -395,6 +404,45 @@ public class ValueSetValidator extends ValueSetProcessBase {
}
}
private void checkValueSetLoad(ValidationProcessInfo info) {
int serverCount = getServerLoad(info);
// There's a trade off here: if we're going to hit the server inside the components, then
// the amount of value set collateral we send is limited, but we pay the price of hitting
// the server multiple times. If, on the other hand, we give up on that, and hit the server
// directly, we have to send value set collateral (though we cache at the higher level)
//
// the cutoff value is chosen experimentally
if (serverCount > 2) {
throw new VSCheckerException("This value set is better processed on the server for performance reasons", null, true);
}
}
private int getServerLoad(ValidationProcessInfo info) {
int serverCount = 0;
if (valueset != null) {
for (ConceptSetComponent inc : valueset.getCompose().getInclude()) {
serverCount = serverCount + checkValueSetLoad(inc, info);
}
for (ConceptSetComponent inc : valueset.getCompose().getExclude()) {
serverCount = serverCount + checkValueSetLoad(inc, info);
}
}
return serverCount;
}
private int checkValueSetLoad(ConceptSetComponent inc, ValidationProcessInfo info) {
int serverCount = 0;
for (UriType uri : inc.getValueSet()) {
ValueSetValidator vsv = getVs(uri.getValue(), info);
serverCount += vsv.getServerLoad(info);
}
CodeSystem cs = resolveCodeSystem(inc.getSystem(), inc.getVersion());
if (cs == null || (cs.getContent() != CodeSystemContentMode.COMPLETE && cs.getContent() != CodeSystemContentMode.FRAGMENT)) {
serverCount++;
}
return serverCount;
}
private boolean checkRequiredSupplements(ValidationProcessInfo info) {
if (!requiredSupplements.isEmpty()) {
String msg= context.formatMessagePlural(requiredSupplements.size(), I18nConstants.VALUESET_SUPPLEMENT_MISSING, CommaSeparatedStringBuilder.build(requiredSupplements));
@ -466,7 +514,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
}
public ValidationResult validateCode(String path, Coding code) throws FHIRException {
opContext.deadCheck();
opContext.deadCheck("validate "+code.toString());
checkValueSetOptions();
String warningMessage = null;
@ -798,7 +846,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
private ValidationResult findCodeInExpansion(Coding code, List<ValueSetExpansionContainsComponent> contains) {
for (ValueSetExpansionContainsComponent containsComponent: contains) {
opContext.deadCheck();
opContext.deadCheck("findCodeInExpansion");
if (containsComponent.getSystem().equals(code.getSystem()) && containsComponent.getCode().equals(code.getCode())) {
ConceptDefinitionComponent ccd = new ConceptDefinitionComponent();
ccd.setCode(containsComponent.getCode());
@ -825,7 +873,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
private boolean checkExpansion(Coding code, List<ValueSetExpansionContainsComponent> contains, VersionInfo vi) {
for (ValueSetExpansionContainsComponent containsComponent: contains) {
opContext.deadCheck();
opContext.deadCheck("checkExpansion: "+code.toString());
if (containsComponent.hasSystem() && containsComponent.hasCode() && containsComponent.getSystem().equals(code.getSystem()) && containsComponent.getCode().equals(code.getCode())) {
vi.setExpansionVersion(containsComponent.getVersion());
return true;
@ -882,7 +930,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
}
for (ConceptDefinitionDesignationComponent ds : cc.getDesignation()) {
opContext.deadCheck();
opContext.deadCheck("validateCode1 "+ds.toString());
if (isOkLanguage(ds.getLanguage())) {
b.append("'"+ds.getValue()+"' ("+ds.getLanguage()+")");
if (code.getDisplay().equalsIgnoreCase(ds.getValue())) {
@ -904,7 +952,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
}
}
for (ConceptReferenceDesignationComponent ds : vs.getCc().getDesignation()) {
opContext.deadCheck();
opContext.deadCheck("validateCode2 "+ds.toString());
if (isOkLanguage(ds.getLanguage())) {
b.append("'"+ds.getValue()+"'");
if (code.getDisplay().equalsIgnoreCase(ds.getValue())) {
@ -1009,7 +1057,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
return null;
// if it has an expansion
for (ValueSetExpansionContainsComponent exp : valueset.getExpansion().getContains()) {
opContext.deadCheck();
opContext.deadCheck("findValueSetRef "+exp.toString());
if (system.equals(exp.getSystem()) && code.equals(exp.getCode())) {
ConceptReferenceComponent cc = new ConceptReferenceComponent();
cc.setDisplay(exp.getDisplay());
@ -1048,7 +1096,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
}
private ConceptDefinitionComponent findCodeInConcept(ConceptDefinitionComponent concept, String code, boolean caseSensitive, AlternateCodesProcessingRules altCodeRules) {
opContext.deadCheck();
opContext.deadCheck("findCodeInConcept: "+code.toString()+", "+concept.toString());
if (code.equals(concept.getCode())) {
return concept;
}
@ -1121,7 +1169,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
int i = 0;
for (ConceptSetComponent vsi : valueset.getCompose().getInclude()) {
opContext.deadCheck();
opContext.deadCheck("scanForCodeInValueSet: "+code.toString());
if (scanForCodeInValueSetInclude(code, sys, problems, i, vsi)) {
return true;
}
@ -1241,7 +1289,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
*/
private boolean checkSystems(List<ValueSetExpansionContainsComponent> contains, String code, Set<String> systems, List<StringWithCode> problems) {
for (ValueSetExpansionContainsComponent c: contains) {
opContext.deadCheck();
opContext.deadCheck("checkSystems "+code.toString());
if (c.getCode().equals(code)) {
systems.add(c.getSystem());
}
@ -1255,7 +1303,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
if (valueset == null) {
return null;
}
opContext.deadCheck();
opContext.deadCheck("codeInValueSet: "+system+"#"+code);
checkCanonical(info.getIssues(), path, valueset, valueset);
Boolean result = false;
VersionInfo vi = new VersionInfo(this);
@ -1290,7 +1338,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
}
private Boolean inComponent(String path, ConceptSetComponent vsi, int vsiIndex, String system, String version, String code, boolean only, ValidationProcessInfo info) throws FHIRException {
opContext.deadCheck();
opContext.deadCheck("inComponent "+vsiIndex);
boolean ok = true;
if (vsi.hasValueSet()) {
@ -1339,6 +1387,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
vs.setUrl(valueset.getUrl()+"--"+vsiIndex);
vs.setVersion(valueset.getVersion());
vs.getCompose().addInclude(vsi);
opContext.deadCheck("hit server "+vs.getVersionedUrl());
ValidationResult res = context.validateCode(options.withNoClient(), new Coding(system, code, null), vs);
if (res.getErrorClass() == TerminologyServiceErrorClass.UNKNOWN || res.getErrorClass() == TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED || res.getErrorClass() == TerminologyServiceErrorClass.VALUESET_UNSUPPORTED) {
if (info != null && res.getErrorClass() == TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED) {
@ -1348,16 +1397,20 @@ public class ValueSetValidator extends ValueSetProcessBase {
info.addIssue(makeIssue(IssueSeverity.WARNING, IssueType.UNKNOWN, path, msg, OpIssueCode.NotFound, null));
for (ConceptReferenceComponent cc : vsi.getConcept()) {
if (cc.getCode().equals(code)) {
opContext.deadCheck("server true");
return true;
}
}
}
info.setErr(TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED);
opContext.deadCheck("server codesystem unsupported");
return null;
}
opContext.deadCheck("server not found");
return false;
}
if (res.getErrorClass() == TerminologyServiceErrorClass.NOSERVICE) {
opContext.deadCheck("server no server");
throw new NoTerminologyServiceException();
}
return res.isOk();
@ -1538,7 +1591,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
}
public boolean validateCodeInConceptList(String code, CodeSystem def, List<ConceptDefinitionComponent> list, AlternateCodesProcessingRules altCodeRules) {
opContext.deadCheck();
opContext.deadCheck("validateCodeInConceptList");
if (def.hasUserData("tx.cs.special")) {
return ((SpecialCodeSystem) def.getUserData("tx.cs.special")).findConcept(new Coding().setCode(code)) != null;
} else if (def.getCaseSensitive()) {
@ -1580,7 +1633,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
inner.put(url, vsc);
return vsc;
}
private Boolean inImport(String path, String uri, String system, String version, String code, ValidationProcessInfo info) throws FHIRException {
ValueSetValidator vs = getVs(uri, info);
if (vs == null) {

View File

@ -36,6 +36,10 @@ public class PackageHackerR5 {
r.hack("http://terminology.hl7.org/CodeSystem/v2-0360-2.3.1", "2.3.1");
}
if ("http://hl7.org/fhir/ValueSet/languages".equals(r.getUrl())) {
r.getResource().setExperimental(false);
}
if ("http://hl7.org/fhir/StructureDefinition/iso21090-nullFlavor".equals(r.getUrl()) && "4.0.1".equals(r.getVersion())) {
StructureDefinition sd = (StructureDefinition) r.getResource();
for (ElementDefinition ed : sd.getSnapshot().getElement()) {

View File

@ -59,7 +59,8 @@ public class FhirLoggingInterceptor implements Interceptor {
headerMap.keySet().forEach(key -> headerMap.get(key).forEach(value -> headerList.add(key + ":" + value)));
if (logger != null) {
logger.logResponse(Integer.toString(response.code()), headerList, bodyBytes);
long responseTimeInMillis = response.receivedResponseAtMillis() - response.sentRequestAtMillis();
logger.logResponse(Integer.toString(response.code()), headerList, bodyBytes, responseTimeInMillis);
}
// Reading byte[] clears body. Need to recreate.

View File

@ -44,6 +44,8 @@ import org.w3c.dom.events.MutationEvent;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.LocatorImpl;
import org.xml.sax.helpers.XMLFilterImpl;
@ -71,6 +73,22 @@ public class XmlLocationAnnotator extends XMLFilterImpl {
((EventTarget) dom).addEventListener("DOMNodeInserted", modListener, true);
}
@Override
public void setProperty(String name, Object value) throws SAXNotRecognizedException, SAXNotSupportedException {
if (!name.equals("http://javax.xml.XMLConstants/property/accessExternalDTD")) {
super.setProperty(name, value);
}
}
@Override
public Object getProperty(String name) throws SAXNotRecognizedException, SAXNotSupportedException {
if (!name.equals("http://javax.xml.XMLConstants/property/accessExternalDTD")) {
return null;
} else {
return super.getProperty(name);
}
}
@Override
public void setDocumentLocator(Locator locator) {
super.setDocumentLocator(locator);

View File

@ -13,6 +13,7 @@ import org.hl7.fhir.r5.utils.validation.IResourceValidator;
import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier;
import org.hl7.fhir.utilities.FhirPublication;
import org.hl7.fhir.utilities.ToolingClientLogger;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.npm.BasePackageCacheManager;
import org.hl7.fhir.utilities.npm.NpmPackage;
import org.hl7.fhir.utilities.validation.ValidationMessage;
@ -341,6 +342,7 @@ public class BaseWorkerContextTests {
public void testValidateCodingWithValueSetChecker() throws IOException {
ValidationOptions validationOptions = new ValidationOptions(FhirPublication.R5).withGuessSystem().withVersionFlexible(false);
ValueSet valueSet = new ValueSet();
valueSet.setUrl(Utilities.makeUuidUrn());
Coding coding = new Coding();
Mockito.doReturn(cacheToken).when(terminologyCache).generateValidationToken(validationOptions, coding, valueSet, expParameters);

View File

@ -172,6 +172,6 @@ class ClientTest {
Mockito.verify(mockLogger, Mockito.times(1))
.logRequest(Mockito.anyString(), Mockito.anyString(), Mockito.anyList(), Mockito.any());
Mockito.verify(mockLogger, Mockito.times(1))
.logResponse(Mockito.anyString(), Mockito.anyList(), Mockito.any());
.logResponse(Mockito.anyString(), Mockito.anyList(), Mockito.any(), Mockito.anyLong());
}
}

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.27-SNAPSHOT</version>
<version>6.3.30-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.27-SNAPSHOT</version>
<version>6.3.30-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -36,7 +36,7 @@ import java.util.List;
public interface ToolingClientLogger {
void logRequest(String method, String url, List<String> headers, byte[] body);
void logResponse(String outcome, List<String> headers, byte[] body);
void logResponse(String outcome, List<String> headers, byte[] body, long length);
String getLastId();
void clearLastId();

View File

@ -64,9 +64,9 @@ public class ManagedWebAccess {
}
public enum WebAccessPolicy {
DIRECT, // open access to the local file system, though access can be restricted only to files under the paths in AllowedPaths
MANAGED, // no access except by the FileSystemProxyProvider
PROHIBITED, // no access at all to File() services
DIRECT, // open access to the web, though access can be restricted only to domains in AllowedDomains
MANAGED, // no access except by the IWebAccessor
PROHIBITED, // no access at all to the web
}
private static WebAccessPolicy accessPolicy = WebAccessPolicy.DIRECT; // for legacy reasons

View File

@ -18,7 +18,9 @@ public class I18nConstants {
public static final String BAD_FILE_PATH_ERROR = "Bad_file_path_error";
public static final String BASE_PROFILE__HAS_NO_TYPE = "Base_profile__has_no_type";
public static final String BASE__DERIVED_PROFILES_HAVE_DIFFERENT_TYPES____VS___ = "Base__Derived_profiles_have_different_types____vs___";
public static final String BINDING_ADDITIONAL = "BINDING_ADDITIONAL";
public static final String BINDING_ADDITIONAL_D = "BINDING_ADDITIONAL_D";
public static final String BINDING_ADDITIONAL_UC = "BINDING_ADDITIONAL_UC";
public static final String BINDING_ADDITIONAL_USAGE = "BINDING_ADDITIONAL_USAGE";
public static final String BINDING_MAX = "BINDING_MAX";
public static final String BUNDLE_BUNDLE_ENTRY_CANONICAL = "Bundle_BUNDLE_Entry_Canonical";
public static final String BUNDLE_BUNDLE_ENTRY_DOCUMENT = "Bundle_BUNDLE_Entry_Document";
@ -1111,4 +1113,7 @@ public class I18nConstants {
public static final String SD_BASE_EXPERIMENTAL = "SD_BASE_EXPERIMENTAL";
public static final String SD_ED_EXPERIMENTAL_BINDING = "SD_ED_EXPERIMENTAL_BINDING";
public static final String VALIDATION_NO_EXPERIMENTAL_CONTENT = "VALIDATION_NO_EXPERIMENTAL_CONTENT";
public static final String SD_ED_ADDITIONAL_BINDING_USAGE_UNKNOWN = "SD_ED_ADDITIONAL_BINDING_USAGE_UNKNOWN";
public static final String SD_ED_ADDITIONAL_BINDING_USAGE_INVALID_ELEMENT = "SD_ED_ADDITIONAL_BINDING_USAGE_INVALID_ELEMENT";
public static final String SD_ED_ADDITIONAL_BINDING_USAGE_INVALID_TYPE = "SD_ED_ADDITIONAL_BINDING_USAGE_INVALID_TYPE";
}

View File

@ -214,6 +214,7 @@ public class RenderingI18nContext extends I18nBase {
public static final String DATA_REND_DATA = "DATA_REND_DATA";
public static final String DATA_REND_DETAILS = "DATA_REND_DETAILS";
public static final String DATA_REND_DETAILS_STATED = "DATA_REND_DETAILS_STATED";
public static final String DATA_REND_DETAILS_STATED_ND = "DATA_REND_DETAILS_STATED_ND";
public static final String DATA_REND_DICOM = "DATA_REND_DICOM";
public static final String DATA_REND_DIM = "DATA_REND_DIM";
public static final String DATA_REND_DURATION = "DATA_REND_DURATION";

View File

@ -8,6 +8,7 @@ import java.text.SimpleDateFormat;
import java.util.*;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import lombok.Getter;
import lombok.Setter;
@ -77,12 +78,13 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
private final FilesystemPackageCacheManagerLocks locks;
private final FilesystemPackageCacheManagerLocks.LockParameters lockParameters;
// When running in testing mode, some packages are provided from the test case repository rather than by the normal means
// the PackageProvider is responsible for this. if no package provider is defined, or it declines to handle the package,
// then the normal means will be used
public interface IPackageProvider {
boolean handlesPackage(String id, String version);
InputStreamWithSrc provide(String id, String version) throws IOException;
}
@ -92,6 +94,7 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
public static final String PACKAGE_VERSION_REGEX_OPT = "^[A-Za-z][A-Za-z0-9\\_\\-]*(\\.[A-Za-z0-9\\_\\-]+)+(\\#[A-Za-z0-9\\-\\_]+(\\.[A-Za-z0-9\\-\\_]+)*)?$";
private static final Logger ourLog = LoggerFactory.getLogger(FilesystemPackageCacheManager.class);
private static final String CACHE_VERSION = "3"; // second version - see wiki page
@Nonnull
private final File cacheFolder;
@ -100,6 +103,7 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
private final Map<String, String> ciList = new HashMap<>();
private JsonArray buildInfo;
private boolean suppressErrors;
@Setter
@Getter
private boolean minimalMemory;
@ -113,9 +117,20 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
@Getter
private final List<PackageServer> packageServers;
@With
@Getter
private final FilesystemPackageCacheManagerLocks.LockParameters lockParameters;
public Builder() throws IOException {
this.cacheFolder = getUserCacheFolder();
this.packageServers = getPackageServersFromFHIRSettings();
this.lockParameters = null;
}
private Builder(File cacheFolder, List<PackageServer> packageServers, FilesystemPackageCacheManagerLocks.LockParameters lockParameters) {
this.cacheFolder = cacheFolder;
this.packageServers = packageServers;
this.lockParameters = lockParameters;
}
private File getUserCacheFolder() throws IOException {
@ -143,17 +158,12 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
return PackageServer.getConfiguredServers();
}
private Builder(File cacheFolder, List<PackageServer> packageServers) {
this.cacheFolder = cacheFolder;
this.packageServers = packageServers;
}
public Builder withCacheFolder(String cacheFolderPath) throws IOException {
File cacheFolder = ManagedFileAccess.file(cacheFolderPath);
if (!cacheFolder.exists()) {
throw new FHIRException("The folder '" + cacheFolder + "' could not be found");
}
return new Builder(cacheFolder, this.packageServers);
return new Builder(cacheFolder, this.packageServers, this.lockParameters);
}
public Builder withSystemCacheFolder() throws IOException {
@ -163,32 +173,33 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
} else {
systemCacheFolder = ManagedFileAccess.file(Utilities.path("/var", "lib", ".fhir", "packages"));
}
return new Builder(systemCacheFolder, this.packageServers);
return new Builder(systemCacheFolder, this.packageServers, this.lockParameters);
}
public Builder withTestingCacheFolder() throws IOException {
return new Builder(ManagedFileAccess.file(Utilities.path("[tmp]", ".fhir", "packages")), this.packageServers);
return new Builder(ManagedFileAccess.file(Utilities.path("[tmp]", ".fhir", "packages")), this.packageServers, this.lockParameters);
}
public FilesystemPackageCacheManager build() throws IOException {
return new FilesystemPackageCacheManager(cacheFolder, packageServers);
final FilesystemPackageCacheManagerLocks locks;
try {
locks = FilesystemPackageCacheManagerLocks.getFilesystemPackageCacheManagerLocks(cacheFolder);
} catch (RuntimeException e) {
if (e.getCause() instanceof IOException) {
throw (IOException) e.getCause();
} else {
throw e;
}
}
return new FilesystemPackageCacheManager(cacheFolder, packageServers, locks, lockParameters);
}
}
private FilesystemPackageCacheManager(@Nonnull File cacheFolder, @Nonnull List<PackageServer> packageServers) throws IOException {
private FilesystemPackageCacheManager(@Nonnull File cacheFolder, @Nonnull List<PackageServer> packageServers, @Nonnull FilesystemPackageCacheManagerLocks locks, @Nullable FilesystemPackageCacheManagerLocks.LockParameters lockParameters) throws IOException {
super(packageServers);
this.cacheFolder = cacheFolder;
try {
this.locks = FilesystemPackageCacheManagerLocks.getFilesystemPackageCacheManagerLocks(cacheFolder);
} catch (RuntimeException e) {
if (e.getCause() instanceof IOException) {
throw (IOException) e.getCause();
} else {
throw e;
}
}
this.locks = locks;
this.lockParameters = lockParameters;
prepareCacheFolder();
}
@ -218,11 +229,35 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
createIniFile();
}
deleteOldTempDirectories();
cleanUpCorruptPackages();
}
return null;
});
}
/*
Look for .lock files that are not actively held by a process. If found, delete the lock file, and the package
referenced.
*/
protected void cleanUpCorruptPackages() throws IOException {
for (File file : Objects.requireNonNull(cacheFolder.listFiles())) {
if (file.getName().endsWith(".lock")) {
if (locks.getCacheLock().canLockFileBeHeldByThisProcess(file)) {
String packageDirectoryName = file.getName().substring(0, file.getName().length() - 5);
log("Detected potential incomplete package installed in cache: " + packageDirectoryName + ". Attempting to delete");
File packageDirectory = ManagedFileAccess.file(Utilities.path(cacheFolder, packageDirectoryName));
if (packageDirectory.exists()) {
Utilities.clearDirectory(packageDirectory.getAbsolutePath());
packageDirectory.delete();
}
file.delete();
log("Deleted potential incomplete package: " + packageDirectoryName);
}
}
}
}
private boolean iniFileExists() throws IOException {
String iniPath = getPackagesIniPath();
File iniFile = ManagedFileAccess.file(iniPath);
@ -421,7 +456,7 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
}
return null;
});
}, lockParameters);
}
/**
@ -465,7 +500,7 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
return null;
}
return loadPackageInfo(path);
});
}, lockParameters);
if (foundPackage != null) {
if (foundPackage.isIndexed()){
return foundPackage;
@ -488,7 +523,7 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
String path = Utilities.path(cacheFolder, foundPackageFolder);
output.checkIndexed(path);
return output;
});
}, lockParameters);
}
}
}
@ -589,7 +624,7 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
throw e;
}
return npmPackage;
});
}, lockParameters);
}
private void log(String s) {

View File

@ -1,14 +1,19 @@
package org.hl7.fhir.utilities.npm;
import lombok.Getter;
import org.hl7.fhir.utilities.TextFile;
import lombok.With;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.filesystem.ManagedFileAccess;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
@ -27,9 +32,23 @@ public class FilesystemPackageCacheManagerLocks {
private final File cacheFolder;
private final Long lockTimeoutTime;
private static final LockParameters lockParameters = new LockParameters();
private final TimeUnit lockTimeoutTimeUnit;
public static class LockParameters {
@Getter @With
private final long lockTimeoutTime;
@Getter @With
private final TimeUnit lockTimeoutTimeUnit;
public LockParameters() {
this(60L, TimeUnit.SECONDS);
}
public LockParameters(long lockTimeoutTime, TimeUnit lockTimeoutTimeUnit) {
this.lockTimeoutTime = lockTimeoutTime;
this.lockTimeoutTimeUnit = lockTimeoutTimeUnit;
}
}
/**
* This method is intended to be used only for testing purposes.
@ -43,21 +62,9 @@ public class FilesystemPackageCacheManagerLocks {
* @throws IOException
*/
public FilesystemPackageCacheManagerLocks(File cacheFolder) throws IOException {
this(cacheFolder, 60L, TimeUnit.SECONDS);
}
private FilesystemPackageCacheManagerLocks(File cacheFolder, Long lockTimeoutTime, TimeUnit lockTimeoutTimeUnit) throws IOException {
this.cacheFolder = cacheFolder;
this.lockTimeoutTime = lockTimeoutTime;
this.lockTimeoutTimeUnit = lockTimeoutTimeUnit;
}
/**
* This method is intended to be used only for testing purposes.
*/
protected FilesystemPackageCacheManagerLocks withLockTimeout(Long lockTimeoutTime, TimeUnit lockTimeoutTimeUnit) throws IOException {
return new FilesystemPackageCacheManagerLocks(cacheFolder, lockTimeoutTime, lockTimeoutTimeUnit);
}
/**
* Returns a single FilesystemPackageCacheManagerLocks instance for the given cacheFolder.
@ -102,6 +109,19 @@ public class FilesystemPackageCacheManagerLocks {
}
return result;
}
public boolean canLockFileBeHeldByThisProcess(File lockFile) throws IOException {
return doWriteWithLock(() -> {
try (FileChannel channel = new RandomAccessFile(lockFile, "rw").getChannel()) {
FileLock fileLock = channel.tryLock(0, Long.MAX_VALUE, false);
if (fileLock != null) {
fileLock.release();
channel.close();
return true;
}
}
return false;});
}
}
public class PackageLock {
@ -114,15 +134,43 @@ public class FilesystemPackageCacheManagerLocks {
this.lock = lock;
}
private void checkForLockFileWaitForDeleteIfExists(File lockFile) throws IOException {
private void checkForLockFileWaitForDeleteIfExists(File lockFile, @Nonnull LockParameters lockParameters) throws IOException {
if (!lockFile.exists()) {
return;
}
// Check if the file is locked by a process. If it is not, it is likely an incomplete package cache install, and
// we should throw an exception.
if (lockFile.isFile()) {
try (FileChannel channel = new RandomAccessFile(lockFile, "rw").getChannel()) {
FileLock fileLock = channel.tryLock(0, Long.MAX_VALUE, false);
if (fileLock != null) {
fileLock.release();
channel.close();
throw new IOException("Lock file exists, but is not locked by a process: " + lockFile.getName());
}
System.out.println("File is locked.");
}
}
try {
waitForLockFileDeletion(lockFile, lockParameters);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IOException("Thread interrupted while waiting for lock", e);
}
}
/*
Wait for the lock file to be deleted. If the lock file is not deleted within the timeout or if the thread is
interrupted, an IOException is thrown.
*/
private void waitForLockFileDeletion(File lockFile, @Nonnull LockParameters lockParameters) throws IOException, InterruptedException {
try (WatchService watchService = FileSystems.getDefault().newWatchService()) {
Path dir = lockFile.getParentFile().toPath();
dir.register(watchService, StandardWatchEventKinds.ENTRY_DELETE);
WatchKey key = watchService.poll(lockTimeoutTime, lockTimeoutTimeUnit);
WatchKey key = watchService.poll(lockParameters.lockTimeoutTime, lockParameters.lockTimeoutTimeUnit);
if (key == null) {
// It is possible that the lock file is deleted before the watch service is registered, so if we timeout at
// this point, we should check if the lock file still exists.
@ -141,24 +189,33 @@ public class FilesystemPackageCacheManagerLocks {
key.reset();
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IOException("Error reading package.", e);
} catch (TimeoutException e) {
throw new IOException("Error reading package.", e);
throw new IOException("Package cache timed out waiting for lock.", e);
}
}
public <T> T doReadWithLock(FilesystemPackageCacheManager.CacheLockFunction<T> f) throws IOException {
/**
* Wraps the execution of a package read function with the appropriate cache, package, and .lock file locking and
* checks.
*
* @param function The function to execute
* @param lockParameters The parameters for the lock
* @return The return of the function
* @param <T> The return type of the function
* @throws IOException If an error occurs while managing locking.
*/
public <T> T doReadWithLock(FilesystemPackageCacheManager.CacheLockFunction<T> function, @Nullable LockParameters lockParameters) throws IOException {
final LockParameters resolvedLockParameters = lockParameters != null ? lockParameters : FilesystemPackageCacheManagerLocks.lockParameters;
cacheLock.getLock().readLock().lock();
lock.readLock().lock();
checkForLockFileWaitForDeleteIfExists(lockFile);
checkForLockFileWaitForDeleteIfExists(lockFile, resolvedLockParameters);
T result = null;
try {
result = f.get();
result = function.get();
} finally {
lock.readLock().unlock();
cacheLock.getLock().readLock().unlock();
@ -166,35 +223,55 @@ public class FilesystemPackageCacheManagerLocks {
return result;
}
public <T> T doWriteWithLock(FilesystemPackageCacheManager.CacheLockFunction<T> f) throws IOException {
/**
* Wraps the execution of a package write function with the appropriate cache, package, and .lock file locking and
* checks.
*
* @param function The function to execute
* @param lockParameters The parameters for the lock
* @return The return of the function
* @param <T> The return type of the function
* @throws IOException If an error occurs while managing locking.
*/
public <T> T doWriteWithLock(FilesystemPackageCacheManager.CacheLockFunction<T> function, @Nullable LockParameters lockParameters) throws IOException {
final LockParameters resolvedLockParameters = lockParameters != null ? lockParameters : FilesystemPackageCacheManagerLocks.lockParameters;
cacheLock.getLock().writeLock().lock();
lock.writeLock().lock();
if (!lockFile.isFile()) {
try {
TextFile.stringToFile("", lockFile);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
/*TODO Eventually, this logic should exist in a Lockfile class so that it isn't duplicated between the main code and
the test code.
*/
try (FileChannel channel = new RandomAccessFile(lockFile, "rw").getChannel()) {
FileLock fileLock = null;
while (fileLock == null) {
fileLock = channel.tryLock(0, Long.MAX_VALUE, true);
if (fileLock == null) {
Thread.sleep(100); // Wait and retry
}
FileLock fileLock = channel.tryLock(0, Long.MAX_VALUE, false);
if (fileLock == null) {
waitForLockFileDeletion(lockFile, resolvedLockParameters);
fileLock = channel.tryLock(0, Long.MAX_VALUE, false);
}
if (fileLock == null) {
throw new IOException("Failed to acquire lock on file: " + lockFile.getName());
}
if (!lockFile.isFile()) {
final ByteBuffer buff = ByteBuffer.wrap(String.valueOf(ProcessHandle.current().pid()).getBytes(StandardCharsets.UTF_8));
channel.write(buff);
}
T result = null;
try {
result = f.get();
result = function.get();
} finally {
lockFile.renameTo(ManagedFileAccess.file(File.createTempFile(lockFile.getName(), ".lock-renamed").getAbsolutePath()));
fileLock.release();
channel.close();
if (!lockFile.delete()) {
lockFile.deleteOnExit();
}
lock.writeLock().unlock();
cacheLock.getLock().writeLock().unlock();
}

View File

@ -12,6 +12,7 @@ import java.util.Map;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.filesystem.ManagedFileAccess;
import org.hl7.fhir.utilities.json.model.JsonArray;
import org.hl7.fhir.utilities.json.model.JsonObject;
@ -43,7 +44,44 @@ public class PackageHacker {
// new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot2/hl7.fhir.r6.search.tgz");
// new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/us/core/v311/package.tgz", "http://hl7.org/fhir/us/core/STU3.1.1");
new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/us/core/v700/package.tgz", "http://hl7.org/fhir/us/core/STU7");
// new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/us/core/v700/package.tgz", "http://hl7.org/fhir/us/core/STU7");
PackageHacker self = new PackageHacker();
// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/hl7.terminology.r4b.tgz");
// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/1.0.0/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/1.0.0/hl7.terminology.r4b.tgz");
// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/2.0.0/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/2.0.0/hl7.terminology.r4b.tgz");
self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/2.1.0/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/2.1.0/hl7.terminology.r4b.tgz");
// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/3.0.0/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/3.0.0/hl7.terminology.r4b.tgz");
// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/3.1.0/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/3.1.0/hl7.terminology.r4b.tgz");
// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/4.0.0/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/4.0.0/hl7.terminology.r4b.tgz");
// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/5.0.0/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/5.0.0/hl7.terminology.r4b.tgz");
// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/5.1.0/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/5.1.0/hl7.terminology.r4b.tgz");
// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/5.2.0/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/5.2.0/hl7.terminology.r4b.tgz");
// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/5.3.0/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/5.3.0/hl7.terminology.r4b.tgz");
// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/5.4.0/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/5.4.0/hl7.terminology.r4b.tgz");
// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/5.5.0/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/5.5.0/hl7.terminology.r4b.tgz");
// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/6.0.0/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/6.0.0/hl7.terminology.r4b.tgz");
// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/6.0.1/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/6.0.1/hl7.terminology.r4b.tgz");
// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/6.0.2/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/6.0.2/hl7.terminology.r4b.tgz");
}
private void cloneToR4B(String src, String dst) throws IOException {
FileInputStream fs = ManagedFileAccess.inStream(src);
NpmPackage pck = NpmPackage.fromPackage(fs);
System.out.println(nice(pck.getNpm()));
JsonObject json = pck.getNpm();
String name = json.asString("name");
json.remove("name");
json.add("name", name.replace(".r4", ".r4b"));
json.remove("fhirVersions");
json.remove("dependencies");
JsonArray fv = new JsonArray();
json.add("fhirVersions", fv);
fv.add("4.3.0");
JsonObject dep = new JsonObject();
json.add("dependencies", dep);
dep.add(VersionUtilities.packageForVersion("4.3.0"), "4.3.0");
pck.save(new FileOutputStream(dst));
}
// private void massEdit(File dir) throws IOException {

View File

@ -33,7 +33,7 @@ public class CacheVerificationLogger implements ToolingClientLogger {
}
@Override
public void logResponse(String outcome, List<String> headers, byte[] body) {
public void logResponse(String outcome, List<String> headers, byte[] body, long start) {
}

View File

@ -1,5 +1,5 @@
package org.hl7.fhir.utilities.xml;
package org.hl7.fhir.utilities.xml;
/*
Copyright (c) 2011+, HL7, Inc.
All rights reserved.
@ -28,80 +28,85 @@ package org.hl7.fhir.utilities.xml;
POSSIBILITY OF SUCH DAMAGE.
*/
import java.io.IOException;
import org.hl7.fhir.utilities.ElementDecoration;
/**
* Generalize
* @author dennisn
*/
public interface IXMLWriter {
public abstract void start() throws IOException;
public abstract void end() throws IOException;
public abstract void attribute(String namespace, String name, String value, boolean onlyIfNotEmpty) throws IOException;
public abstract void attribute(String namespace, String name, String value) throws IOException;
public abstract void attribute(String name, String value, boolean onlyIfNotEmpty) throws IOException;
public abstract void attribute(String name, String value) throws IOException;
public abstract void attributeNoLines(String name, String value) throws IOException;
public abstract boolean namespaceDefined(String namespace);
public abstract boolean abbreviationDefined(String abbreviation);
public abstract String getDefaultNamespace();
public abstract void namespace(String namespace) throws IOException;
public abstract void setDefaultNamespace(String namespace) throws IOException;
public abstract void namespace(String namespace, String abbreviation) throws IOException;
public abstract void comment(String comment, boolean doPretty) throws IOException;
public abstract void decorate(ElementDecoration decoration) throws IOException;
public abstract void setSchemaLocation(String ns, String loc) throws IOException;
public abstract void enter(String name) throws IOException;
public abstract void enter(String namespace, String name) throws IOException;
public abstract void enter(String namespace, String name, String comment) throws IOException;
public abstract void exit() throws IOException;
public abstract void exit(String name) throws IOException;
public abstract void exit(String namespace, String name) throws IOException;
public abstract void exitToLevel(int count) throws IOException;
public abstract void element(String namespace, String name, String content, boolean onlyIfNotEmpty) throws IOException;
public abstract void element(String namespace, String name, String content, String comment) throws IOException;
public abstract void element(String namespace, String name, String content) throws IOException;
public abstract void element(String name, String content, boolean onlyIfNotEmpty) throws IOException;
public abstract void element(String name, String content) throws IOException;
public abstract void element(String name) throws IOException;
public abstract void text(String content) throws IOException;
public abstract void text(String content, boolean dontEscape) throws IOException;
public abstract void cData(String text) throws IOException;
public abstract void writeBytes(byte[] bytes) throws IOException;
public abstract boolean isPretty() throws IOException;
public abstract void setPretty(boolean pretty) throws IOException;
/**
* Start comment inserts a <!-- in the stream, but allows the user to
* go on creating xml content as usual, with proper formatting applied etc.
* Any comments inserted inside a comment will be terminated with -- > instead of -->
* so the comment doesn't close prematurely.
* @throws IOException
*/
public abstract void startCommentBlock() throws IOException;
public abstract void endCommentBlock() throws IOException;
public abstract void escapedText(String content) throws IOException;
// this is only implemented by an implementation that is producing an xhtml representation, and is able to render elements as hyperlinks
public abstract void link(String href);
public abstract void anchor(String name);
public abstract void externalLink(String ref) throws IOException;
import java.io.IOException;
import org.hl7.fhir.utilities.ElementDecoration;
/**
* Generalize
* @author dennisn
*/
public interface IXMLWriter {
public abstract void start() throws IOException;
public abstract void end() throws IOException;
public abstract void attribute(String namespace, String name, String value, boolean onlyIfNotEmpty) throws IOException;
public abstract void attribute(String namespace, String name, String value) throws IOException;
public abstract void attribute(String name, String value, boolean onlyIfNotEmpty) throws IOException;
public abstract void attribute(String name, String value) throws IOException;
public abstract void attributeNoLines(String name, String value) throws IOException;
public abstract boolean namespaceDefined(String namespace);
public abstract boolean abbreviationDefined(String abbreviation);
public abstract String getDefaultNamespace();
public abstract void namespace(String namespace) throws IOException;
public abstract void setDefaultNamespace(String namespace) throws IOException;
public abstract void namespace(String namespace, String abbreviation) throws IOException;
public abstract void comment(String comment, boolean doPretty) throws IOException;
public abstract void decorate(ElementDecoration decoration) throws IOException;
public abstract void setSchemaLocation(String ns, String loc) throws IOException;
public abstract void enter(String name) throws IOException;
public abstract void enter(String namespace, String name) throws IOException;
public abstract void enter(String namespace, String name, String comment) throws IOException;
public abstract void exit() throws IOException;
public abstract void exit(String name) throws IOException;
public abstract void exit(String namespace, String name) throws IOException;
public abstract void exitToLevel(int count) throws IOException;
public abstract void element(String namespace, String name, String content, boolean onlyIfNotEmpty) throws IOException;
public abstract void element(String namespace, String name, String content, String comment) throws IOException;
public abstract void element(String namespace, String name, String content) throws IOException;
public abstract void element(String name, String content, boolean onlyIfNotEmpty) throws IOException;
public abstract void element(String name, String content) throws IOException;
public abstract void element(String name) throws IOException;
public abstract void text(String content) throws IOException;
public abstract void text(String content, boolean dontEscape) throws IOException;
public abstract void cData(String text) throws IOException;
public abstract void writeBytes(byte[] bytes) throws IOException;
public abstract boolean isPretty() throws IOException;
public abstract void setPretty(boolean pretty) throws IOException;
/**
* Start comment inserts a <!-- in the stream, but allows the user to
* go on creating xml content as usual, with proper formatting applied etc.
* Any comments inserted inside a comment will be terminated with -- > instead of -->
* so the comment doesn't close prematurely.
* @throws IOException
*/
public abstract void startCommentBlock() throws IOException;
public abstract void endCommentBlock() throws IOException;
public abstract void escapedText(String content) throws IOException;
// this is only implemented by an implementation that is producing an xhtml representation, and is able to render elements as hyperlinks
public abstract void link(String href);
public abstract void anchor(String name);
public abstract void externalLink(String ref) throws IOException;
// this is only implemented by an implementation that is producing an xhtml representation and handles ellipsing elements
public abstract boolean canElide();
public abstract void elide() throws IOException;
public abstract void attributeElide();
}

View File

@ -13,7 +13,9 @@ Attempt_to_a_slice_an_element_that_does_not_repeat__from__in_ = Attempt to a sli
Attempt_to_replace_element_name_for_a_nonchoice_type=Attempt to replace element name for a non-choice type
Attempt_to_use_Terminology_server_when_no_Terminology_server_is_available = Attempt to use Terminology server when no Terminology server is available
Attempt_to_use_a_snapshot_on_profile__as__before_it_is_generated = Attempt to use a snapshot on profile ''{0}'' as {1} before it is generated
BINDING_ADDITIONAL = {0} specified in an additional binding
BINDING_ADDITIONAL_D = {0} specified in an additional binding
BINDING_ADDITIONAL_UC = {0} specified in an additional binding which applies because {1}
BINDING_ADDITIONAL_USAGE = {0} = {1}
BINDING_MAX = {0} specified in the max binding
BUNDLE_BUNDLE_ENTRY_FOUND_MULTIPLE = Found {0} matches for ''{1}'' in the bundle ({2})
BUNDLE_BUNDLE_ENTRY_FOUND_MULTIPLE_FRAGMENT = Found {0} matches for fragment {2} in resource ''{1}'' in the bundle ({3})
@ -1029,7 +1031,7 @@ VALUESET_SUPPLEMENT_MISSING_one = Required supplement not found: {1}
VALUESET_SUPPLEMENT_MISSING_other = Required supplements not found: {1}
VALUESET_TOO_COSTLY = The value set ''{0}'' expansion has too many codes to display ({1})
VALUESET_TOO_COSTLY_COUNT = The value set ''{0}'' expansion has {2} codes, which is too many to display ({1})
VALUESET_TOO_COSTLY_TIME = The value set ''{0}'' expansion took too long to process (>{1}sec)
VALUESET_TOO_COSTLY_TIME = The value set ''{0}'' {2} took too long to process (>{1}sec)
VALUESET_UNC_SYSTEM_WARNING = Unknown System ''{0}'' specified, so Concepts and Filters can''t be checked (Details: {1})
VALUESET_UNC_SYSTEM_WARNING_VER = Unknown System/Version ''{0}'' specified, so Concepts and Filters can''t be checked (Details: {1})
VALUESET_UNKNOWN_FILTER_PROPERTY = The property ''{0}'' is not known for the system ''{1}'', so may not be understood by the terminology ecosystem. Known properties for this system: {2}
@ -1138,8 +1140,12 @@ TYPE_SPECIFIC_CHECKS_DT_XHTML_LITERAL_HREF = Hyperlink scheme ''{3}'' in ''{0}''
SM_TARGET_TYPE_UNKNOWN = The type of the target variable is not known: {0}
XHTML_XHTML_ATTRIBUTE_XML_SPACE = The attribute 'xml:space' is legal but has a fixed value of 'preserve'. It''s use is discouraged
VALIDATION_HL7_PUBLISHER_MULTIPLE_WGS = This resource has more than workgroup extension (http://hl7.org/fhir/StructureDefinition/structuredefinition-wg)
NO_VALID_DISPLAY_FOUND_NONE_FOR_LANG = Wrong Display Name ''{0}'' for {1}#{2}. There are no valid display names found for language(s) ''{3}''. Default display is ''{4}''
NO_VALID_DISPLAY_FOUND_NONE_FOR_LANG_OK = There are no valid display names found for the code {1}#{2} for language(s) ''{3}''. The display is ''{4}'' the default language display
NO_VALID_DISPLAY_FOUND_NONE_FOR_LANG_ERR = Wrong Display Name ''{0}'' for {1}#{2}. There are no valid display names found for language(s) ''{3}''. Default display is ''{4}''
NO_VALID_DISPLAY_AT_ALL = Cannot validate display Name ''{0}'' for {1}#{2}: No displays are known
SD_BASE_EXPERIMENTAL = The definition builds on ''{0}'' which is experimental, but this definition is not labeled as experimental
SD_ED_EXPERIMENTAL_BINDING = The definition for the element ''{0}'' binds to the value set ''{1}'' which is experimental, but this structure is not labeled as experimental
VALIDATION_NO_EXPERIMENTAL_CONTENT = Experimental content is not allowed in this context
SD_ED_ADDITIONAL_BINDING_USAGE_UNKNOWN = The Usage Context {0}#{1} is not recognised and may not be correct
SD_ED_ADDITIONAL_BINDING_USAGE_INVALID_ELEMENT = The Usage Context {0}#{1} is a reference to an element that does not exist
SD_ED_ADDITIONAL_BINDING_USAGE_INVALID_TYPE = The Usage Context value must be of type {1} not {0}

View File

@ -207,7 +207,8 @@ DATA_REND_COND = Condition
DATA_REND_COUNT = Count {0}
DATA_REND_DATA = Data: {0}
DATA_REND_DETAILS = (Details: {0} code
DATA_REND_DETAILS_STATED = (Details: {0} code {1} {2} {3} '', stated as '' {4} {5}
DATA_REND_DETAILS_STATED = (Details: {0} code {1} = ''{2}'')
DATA_REND_DETAILS_STATED_ND = (Details: {0} code {1})
DATA_REND_DICOM = DICOM
DATA_REND_DIM = Dimensions: {0}
DATA_REND_DURATION = Duration {0}

View File

@ -1,7 +1,7 @@
package org.hl7.fhir.utilities.npm;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.filesystem.ManagedFileAccess;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -12,10 +12,12 @@ import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class FilesystemPackageManagerLockTests {
@ -49,13 +51,13 @@ public class FilesystemPackageManagerLockTests {
packageLock.doWriteWithLock(() -> {
assertThat(packageLock.getLockFile()).exists();
return null;
});
}, null);
assertThat(packageLock.getLockFile()).doesNotExist();
packageLock.doReadWithLock(() -> {
assertThat(packageLock.getLockFile()).doesNotExist();
return null;
});
}, null);
}
@Test void testNoPackageWriteOrReadWhileWholeCacheIsLocked() throws IOException, InterruptedException {
@ -87,7 +89,7 @@ public class FilesystemPackageManagerLockTests {
packageLock.doWriteWithLock(() -> {
assertThat(cacheLockFinished.get()).isTrue();
return null;
});
}, null);
} catch (IOException e) {
throw new RuntimeException(e);
}
@ -97,7 +99,7 @@ public class FilesystemPackageManagerLockTests {
packageLock.doReadWithLock(() -> {
assertThat(cacheLockFinished.get()).isTrue();
return null;
});
}, null);
} catch (IOException e) {
throw new RuntimeException(e);
}
@ -116,6 +118,23 @@ public class FilesystemPackageManagerLockTests {
}
}
@Test void testWhenLockIsntHeld_canLockFileBeHeldByThisProcessIsTrue() throws IOException {
File lockFile = getPackageLockFile();
lockFile.createNewFile();
Assertions.assertTrue(filesystemPackageCacheLockManager.getCacheLock().canLockFileBeHeldByThisProcess(lockFile));
}
@Test void testWhenLockIsHelp_canLockFileBeHeldByThisProcessIsFalse() throws InterruptedException, TimeoutException, IOException {
File lockFile = getPackageLockFile();
Thread lockThread = LockfileTestProcessUtility.lockWaitAndDeleteInNewProcess(cachePath, DUMMY_PACKAGE + ".lock", 2);
LockfileTestUtility.waitForLockfileCreation(cacheDirectory.getAbsolutePath(), DUMMY_PACKAGE + ".lock");
Assertions.assertFalse(filesystemPackageCacheLockManager.getCacheLock().canLockFileBeHeldByThisProcess(lockFile));
lockThread.join();
}
@Test void testSinglePackageWriteMultiPackageRead() throws IOException {
final FilesystemPackageCacheManagerLocks.PackageLock packageLock = filesystemPackageCacheLockManager.getPackageLock(DUMMY_PACKAGE);
AtomicInteger writeCounter = new AtomicInteger(0);
@ -133,7 +152,7 @@ public class FilesystemPackageManagerLockTests {
assertThat(writeCount).isEqualTo(1);
writeCounter.decrementAndGet();
return null;
});
}, null);
} catch (IOException e) {
throw new RuntimeException(e);
}
@ -156,7 +175,7 @@ public class FilesystemPackageManagerLockTests {
}
readCounter.decrementAndGet();
return null;
});
}, null);
} catch (IOException e) {
throw new RuntimeException(e);
}
@ -179,49 +198,47 @@ public class FilesystemPackageManagerLockTests {
}
@Test
public void testReadWhenLockedByFileTimesOut() throws IOException {
FilesystemPackageCacheManagerLocks shorterTimeoutManager = filesystemPackageCacheLockManager.withLockTimeout(3L, TimeUnit.SECONDS);
public void testReadWhenLockedByFileTimesOut() throws InterruptedException, TimeoutException, IOException {
FilesystemPackageCacheManagerLocks shorterTimeoutManager = filesystemPackageCacheLockManager;
final FilesystemPackageCacheManagerLocks.PackageLock packageLock = shorterTimeoutManager.getPackageLock(DUMMY_PACKAGE);
File lockFile = createPackageLockFile();
File lockFile = getPackageLockFile();
Thread lockThread = LockfileTestProcessUtility.lockWaitAndDeleteInNewProcess(cachePath, lockFile.getName(), 5);
LockfileTestUtility.waitForLockfileCreation(cachePath,lockFile.getName());
Exception exception = assertThrows(IOException.class, () -> {
packageLock.doReadWithLock(() -> {
assertThat(lockFile).exists();
return null;
});
}, new FilesystemPackageCacheManagerLocks.LockParameters(3L, TimeUnit.SECONDS));
});
assertThat(exception.getMessage()).contains("Error reading package");
assertThat(exception.getMessage()).contains("Package cache timed out waiting for lock");
assertThat(exception.getCause().getMessage()).contains("Timeout waiting for lock file deletion: " + lockFile.getName());
lockThread.join();
}
@Test
public void testReadWhenLockFileIsDeleted() throws IOException {
FilesystemPackageCacheManagerLocks shorterTimeoutManager = filesystemPackageCacheLockManager.withLockTimeout(5L, TimeUnit.SECONDS);
final FilesystemPackageCacheManagerLocks.PackageLock packageLock = shorterTimeoutManager.getPackageLock(DUMMY_PACKAGE);
File lockFile = createPackageLockFile();
Thread t = new Thread(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
lockFile.delete();
});
t.start();
@Test
public void testReadWhenLockFileIsDeleted() throws InterruptedException, TimeoutException, IOException {
final FilesystemPackageCacheManagerLocks.PackageLock packageLock = filesystemPackageCacheLockManager.getPackageLock(DUMMY_PACKAGE);
final File lockFile = getPackageLockFile();
Thread lockThread = LockfileTestProcessUtility.lockWaitAndDeleteInNewProcess(cachePath, lockFile.getName(), 5);
LockfileTestUtility.waitForLockfileCreation(cachePath,lockFile.getName());
packageLock.doReadWithLock(() -> {
assertThat(lockFile).doesNotExist();
return null;
});
}, new FilesystemPackageCacheManagerLocks.LockParameters(10L, TimeUnit.SECONDS));
lockThread.join();
}
private File createPackageLockFile() throws IOException {
File lockFile = Path.of(cachePath, DUMMY_PACKAGE + ".lock").toFile();
TextFile.stringToFile("", lockFile);
return lockFile;
private File getPackageLockFile() {
return Path.of(cachePath, DUMMY_PACKAGE + ".lock").toFile();
}
}

View File

@ -2,6 +2,7 @@ package org.hl7.fhir.utilities.npm;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.io.File;
@ -13,6 +14,8 @@ import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
@ -20,6 +23,7 @@ import javax.annotation.Nonnull;
import org.hl7.fhir.utilities.IniFile;
import org.hl7.fhir.utilities.filesystem.ManagedFileAccess;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledOnOs;
import org.junit.jupiter.api.condition.EnabledOnOs;
@ -113,6 +117,97 @@ public class FilesystemPackageManagerTests {
assertEquals( System.getenv("ProgramData") + "\\.fhir\\packages", folder.getAbsolutePath());
}
@Test
public void testCorruptPackageCleanup() throws IOException {
File cacheDirectory = ManagedFileAccess.fromPath(Files.createTempDirectory("fpcm-multithreadingTest"));
File dummyPackage = createDummyPackage(cacheDirectory, "example.fhir.uv.myig", "1.2.3");
File dummyLockFile = createDummyLockFile(cacheDirectory, "example.fhir.uv.myig" , "1.2.3");
assertThat(dummyPackage).isDirectory();
assertThat(dummyPackage).exists();
assertThat(dummyLockFile).exists();
FilesystemPackageCacheManager filesystemPackageCacheManager = new FilesystemPackageCacheManager.Builder().withCacheFolder(cacheDirectory.getAbsolutePath()).build();
assertThat(dummyPackage).doesNotExist();
assertThat(dummyLockFile).doesNotExist();
}
@Test
public void testLockedPackageIsntCleanedUp() throws IOException, InterruptedException, TimeoutException {
File cacheDirectory = ManagedFileAccess.fromPath(Files.createTempDirectory("fpcm-multithreadingTest"));
File dummyPackage = createDummyPackage(cacheDirectory, "example.fhir.uv.myig", "1.2.3");
Thread lockThread = LockfileTestProcessUtility.lockWaitAndDeleteInNewProcess(cacheDirectory.getAbsolutePath(), "example.fhir.uv.myig#1.2.3.lock", 2);
LockfileTestUtility.waitForLockfileCreation(cacheDirectory.getAbsolutePath(), "example.fhir.uv.myig#1.2.3.lock");
File dummyLockFile = ManagedFileAccess.file(cacheDirectory.getAbsolutePath(), "example.fhir.uv.myig#1.2.3.lock");
assertThat(dummyPackage).isDirectory();
assertThat(dummyPackage).exists();
assertThat(dummyLockFile).exists();
FilesystemPackageCacheManager filesystemPackageCacheManager = new FilesystemPackageCacheManager.Builder().withCacheFolder(cacheDirectory.getAbsolutePath()).build();
assertThat(dummyPackage).exists();
assertThat(dummyLockFile).exists();
lockThread.join();
}
@Test
public void testTimeoutForLockedPackageRead() throws IOException, InterruptedException, TimeoutException {
String pcmPath = ManagedFileAccess.fromPath(Files.createTempDirectory("fpcm-multithreadingTest")).getAbsolutePath();
final FilesystemPackageCacheManager pcm = new FilesystemPackageCacheManager.Builder()
.withCacheFolder(pcmPath)
.withLockParameters(new FilesystemPackageCacheManagerLocks.LockParameters(5,TimeUnit.SECONDS))
.build();
Assertions.assertTrue(pcm.listPackages().isEmpty());
Thread lockThread = LockfileTestProcessUtility.lockWaitAndDeleteInNewProcess(pcmPath, "example.fhir.uv.myig#1.2.3.lock", 10);
File directory = ManagedFileAccess.file(pcmPath, "example.fhir.uv.myig#1.2.3" );
directory.mkdir();
LockfileTestUtility.waitForLockfileCreation(pcmPath, "example.fhir.uv.myig#1.2.3.lock");
IOException exception = assertThrows(IOException.class, () -> pcm.loadPackageFromCacheOnly("example.fhir.uv.myig", "1.2.3"));
assertThat(exception.getMessage()).contains("Package cache timed out waiting for lock");
assertThat(exception.getCause().getMessage()).contains("Timeout waiting for lock file deletion");
lockThread.join();
}
@Test
public void testReadFromCacheOnlyWaitsForLockDelete() throws IOException, InterruptedException, TimeoutException {
String pcmPath = ManagedFileAccess.fromPath(Files.createTempDirectory("fpcm-multithreadingTest")).getAbsolutePath();
final FilesystemPackageCacheManager pcm = new FilesystemPackageCacheManager.Builder().withCacheFolder(pcmPath).build();
Assertions.assertTrue(pcm.listPackages().isEmpty());
pcm.addPackageToCache("example.fhir.uv.myig", "1.2.3", this.getClass().getResourceAsStream("/npm/dummy-package.tgz"), "https://packages.fhir.org/example.fhir.uv.myig/1.2.3");
String packageAndVersion = "example.fhir.uv.myig#1.2.3";
//Now sneak in a new lock file and directory:
File directory = ManagedFileAccess.file(pcmPath, packageAndVersion);
directory.mkdir();
Thread lockThread = LockfileTestProcessUtility.lockWaitAndDeleteInNewProcess(pcmPath, "example.fhir.uv.myig#1.2.3.lock", 5);
LockfileTestUtility.waitForLockfileCreation(pcmPath, "example.fhir.uv.myig#1.2.3.lock");
NpmPackage npmPackage = pcm.loadPackageFromCacheOnly("example.fhir.uv.myig", "1.2.3");
assertThat(npmPackage.id()).isEqualTo("example.fhir.uv.myig");
lockThread.join();
}
/**
We repeat the same tests multiple times here, in order to catch very rare edge cases.
*/
@ -126,16 +221,16 @@ public class FilesystemPackageManagerTests {
return params.stream();
}
private void createDummyTemp(File cacheDirectory, String lowerCase) throws IOException {
createDummyPackage(cacheDirectory, lowerCase);
private File createDummyTemp(File cacheDirectory, String lowerCase) throws IOException {
return createDummyPackage(cacheDirectory, lowerCase);
}
private void createDummyPackage(File cacheDirectory, String packageName, String packageVersion) throws IOException {
private File createDummyPackage(File cacheDirectory, String packageName, String packageVersion) throws IOException {
String directoryName = packageName + "#" + packageVersion;
createDummyPackage(cacheDirectory, directoryName);
return createDummyPackage(cacheDirectory, directoryName);
}
private static void createDummyPackage(File cacheDirectory, String directoryName) throws IOException {
private static File createDummyPackage(File cacheDirectory, String directoryName) throws IOException {
File packageDirectory = ManagedFileAccess.file(cacheDirectory.getAbsolutePath(), directoryName);
packageDirectory.mkdirs();
@ -144,6 +239,16 @@ public class FilesystemPackageManagerTests {
wr.write("Ain't nobody here but us chickens");
wr.flush();
wr.close();
return packageDirectory;
}
private File createDummyLockFile(File cacheDirectory, String packageName, String packageVersion) throws IOException {
final File dummyLockFile = ManagedFileAccess.file(cacheDirectory.getAbsolutePath(), packageName + "#" + packageVersion + ".lock");
final FileWriter wr = new FileWriter(dummyLockFile);
wr.write("Ain't nobody here but us chickens");
wr.flush();
wr.close();
return dummyLockFile;
}
private void assertThatDummyTempExists(File cacheDirectory, String dummyTempPackage) throws IOException {
@ -241,13 +346,13 @@ public class FilesystemPackageManagerTests {
@MethodSource("packageCacheMultiThreadTestParams")
@ParameterizedTest
public void packageCacheMultiThreadTest(final int threadTotal, final int packageCacheManagerTotal) throws IOException {
String pcmPath = ManagedFileAccess.fromPath(Files.createTempDirectory("fpcm-multithreadingTest")).getAbsolutePath();
System.out.println("Using temp pcm path: " + pcmPath);
FilesystemPackageCacheManager[] packageCacheManagers = new FilesystemPackageCacheManager[packageCacheManagerTotal];
Random rand = new Random();
final AtomicInteger totalSuccessful = new AtomicInteger();
final ConcurrentHashMap successfulThreads = new ConcurrentHashMap();
final ConcurrentHashMap<Long, Integer> successfulThreads = new ConcurrentHashMap<>();
List<Thread> threads = new ArrayList<>();
for (int i = 0; i < threadTotal; i++) {
final int index = i;
@ -256,22 +361,27 @@ public class FilesystemPackageManagerTests {
System.out.println("Thread #" + index + ": " + Thread.currentThread().getId() + " started");
final int randomPCM = rand.nextInt(packageCacheManagerTotal);
final int randomOperation = rand.nextInt(4);
final String operationName;
if (packageCacheManagers[randomPCM] == null) {
packageCacheManagers[randomPCM] = new FilesystemPackageCacheManager.Builder().withCacheFolder(pcmPath).build();
}
FilesystemPackageCacheManager pcm = packageCacheManagers[randomPCM];
if (randomOperation == 0) {
operationName = "addPackageToCache";
pcm.addPackageToCache("example.fhir.uv.myig", "1.2.3", this.getClass().getResourceAsStream("/npm/dummy-package.tgz"), "https://packages.fhir.org/example.fhir.uv.myig/1.2.3");
} else if (randomOperation == 1) {
operationName = "clear";
pcm.clear();
} else if (randomOperation == 2) {
operationName = "loadPackageFromCacheOnly";
pcm.loadPackageFromCacheOnly("example.fhir.uv.myig", "1.2.3");
} else {
operationName = "removePackage";
pcm.removePackage("example.fhir.uv.myig", "1.2.3");
}
totalSuccessful.incrementAndGet();
successfulThreads.put(Thread.currentThread().getId(), index);
System.out.println("Thread #" + index + ": " + Thread.currentThread().getId() + " completed");
System.out.println("Thread #" + index + ": " + Thread.currentThread().getId() + " completed. Ran: " + operationName);
} catch (Exception e) {
e.printStackTrace();
System.err.println("Thread #" + index + ": " + Thread.currentThread().getId() + " failed");

View File

@ -0,0 +1,122 @@
package org.hl7.fhir.utilities.npm;
import org.hl7.fhir.utilities.filesystem.ManagedFileAccess;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
/**
* FilesystemPackageCacheManagerLocks relies on the existence of .lock files to prevent access to packages being written
* by processes outside the current JVM. Testing this functionality means creating a process outside the JUnit test JVM,
* which is achieved by running a separate Java process.
* <p/>
* Intended usage:
* <p/>
* The helper method {@link #lockWaitAndDeleteInNewProcess(String, String, int)} is the intended starting point for
* using this class.
* <p/>
*
*
* This class deliberately avoids using any dependencies outside java.*, which avoids having to construct a classpath
* for the separate process.
*/
public class LockfileTestProcessUtility {
/**
* Main method to allow running this class.
* <p/
* It is not recommended to call this method directly. Instead, use the provided {@link #lockWaitAndDeleteInNewProcess(String, String, int)} method.
*
* @param args The arguments to the main method. The first argument is the path to create the lockfile in, the second
* argument is the name of the lockfile, and the third argument is the number of seconds to wait before
* deleting the lockfile.
*/
public static void main(String[] args) {
String path = args[0];
String lockFileName = args[1];
int seconds = Integer.parseInt(args[2]);
try {
lockWaitAndDelete(path, lockFileName, seconds);
} catch (InterruptedException | IOException e) {
throw new RuntimeException(e);
}
}
/**
* Static helper method that starts a new process, creates a lock file in the path and waits for a specified number of
* seconds before deleting it.
* <p/>
* This method calls the {@link #main(String[])} method in a new process.
*
* @param path The path to create the lockfile in
* @param lockFileName The name of the lockfile
* @param seconds The number of seconds to wait before deleting the lockfile
* @return The thread wrapping the process execution. This can be used to wait for the process to complete, so that
* System.out and System.err can be processed before tests return results.
*/
public static Thread lockWaitAndDeleteInNewProcess(String path, String lockFileName, int seconds) {
Thread t = new Thread(() -> {
ProcessBuilder processBuilder = new ProcessBuilder("java", "-cp", "target/test-classes", LockfileTestProcessUtility.class.getName(), path, lockFileName, Integer.toString(seconds));
try {
Process process = processBuilder.start();
process.getErrorStream().transferTo(System.err);
process.getInputStream().transferTo(System.out);
process.waitFor();
} catch (IOException | InterruptedException e) {
throw new RuntimeException(e);
}
});
t.start();
return t;
}
/**
* The actual logic to create a .lock file.
* <p/>
* This should match the logic in FilesystemPackageCacheManagerLocks
* <p/>
*
* @param path The path to create the lockfile in
* @param lockFileName The name of the lockfile
* @param seconds The number of seconds to wait before deleting the lockfile
* @throws InterruptedException If the thread is interrupted while waiting
* @throws IOException If there is an error accessing the file system
*/
/* TODO Eventually, this logic should exist in a Lockfile class so that it isn't duplicated between the main code and
the test code.
*/
private static void lockWaitAndDelete(String path, String lockFileName, int seconds) throws InterruptedException, IOException {
File lockFile = Paths.get(path,lockFileName).toFile();
try (FileChannel channel = new RandomAccessFile(lockFile.getAbsolutePath(), "rw").getChannel()) {
FileLock fileLock = channel.tryLock(0, Long.MAX_VALUE, false);
if (fileLock != null) {
final ByteBuffer buff = ByteBuffer.wrap("Hello world".getBytes(StandardCharsets.UTF_8));
channel.write(buff);
System.out.println("File "+lockFileName+" is locked. Waiting for " + seconds + " seconds to release. ");
Thread.sleep(seconds * 1000L);
lockFile.renameTo(ManagedFileAccess.file(File.createTempFile(lockFile.getName(), ".lock-renamed").getAbsolutePath()));
fileLock.release();
channel.close();
System.out.println(System.currentTimeMillis());
System.out.println("File "+lockFileName+" is released.");
lockFile.delete();
}}finally {
if (lockFile.exists()) {
lockFile.delete();
}
}
}
}

View File

@ -0,0 +1,78 @@
package org.hl7.fhir.utilities.npm;
import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
import org.apache.commons.io.monitor.FileAlterationMonitor;
import org.apache.commons.io.monitor.FileAlterationObserver;
import java.io.*;
import java.nio.file.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class LockfileTestUtility {
/**
* Wait for the lock file to be created in the given path.
* <p/>
* Normally, within the same JVM, you could use a CountdownLatch for the same purpose, but since this the lock file is
* being created in a separate process, we need to use a mechanism that doesn't rely on shared threads.
*
* @param path The path containing the lock file
* @param lockFileName The name of the lock file
* @throws InterruptedException If the thread is interrupted while waiting
* @throws TimeoutException If the lock file is not created within 10 seconds
*/
public static void waitForLockfileCreation(String path, String lockFileName) throws InterruptedException, TimeoutException {
CountDownLatch latch = new CountDownLatch(1);
FileAlterationMonitor monitor = new FileAlterationMonitor(100);
FileAlterationObserver observer = new FileAlterationObserver(path);
observer.addListener(new FileAlterationListenerAdaptor(){
@Override
public void onStart(FileAlterationObserver observer) {
if (Files.exists(Paths.get(path, lockFileName))) {
latch.countDown();
}
}
@Override
public void onFileCreate(File file) {
System.out.println("File created: " + file.getName());
latch.countDown();
}
});
monitor.addObserver(observer);
try {
monitor.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
boolean success = latch.await(10, TimeUnit.SECONDS);
try {
monitor.stop();
} catch (Exception e) {
throw new RuntimeException(e);
}
if (!success) {
throw new TimeoutException("Timed out waiting for lock file creation: " + lockFileName);
}
// TODO This is a workaround for an edge condition that shows up with testing, where the lock is not reflected in
// the file system immediately. It is unlikely to appear in production environments. Should it occur, it will
// result in a lock file being erroneously reported as not having an owning process, and will cause a package to
// fail to be loaded from that cache until the lock is cleaned up by cache initialization.
Thread.sleep(100);
}
}

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.27-SNAPSHOT</version>
<version>6.3.30-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.27-SNAPSHOT</version>
<version>6.3.30-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -1192,6 +1192,34 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
}
protected int countFragmentMatches(Element element, String fragment, NodeStack stack) {
int count = countFragmentMatches(element, fragment);
if (count == 0 && element.isResource() && element.hasParentForValidator()) {
Element bnd = getElementBundle(element);
if (bnd != null) {
// in this case, we look into the parent - if there is one - and if it's a bundle, we look at the entries (but not in them)
for (Element be : bnd.getChildrenByName("entry")) {
String id = be.getIdBase();
if (fragment.equals(id)) {
count++;
}
}
}
}
return count;
}
private Element getElementBundle(Element element) {
Element p = element.getParentForValidator();
if (p != null) {
Element b = p.getParentForValidator();
if (b != null && b.fhirType().equals("Bundle")) {
return b;
}
}
return null;
}
protected int countFragmentMatches(Element element, String fragment) {
int count = 0;
if (fragment.equals(element.getIdBase())) {

View File

@ -130,7 +130,7 @@ public class CliContext {
private boolean showTimes = false;
@JsonProperty("locale")
private String locale = Locale.ENGLISH.getDisplayLanguage();
private String locale = Locale.ENGLISH.toLanguageTag();
@JsonProperty("locations")
private Map<String, String> locations = new HashMap<String, String>();

View File

@ -529,14 +529,18 @@ public class ValidationService {
}
@Nonnull
protected ValidationEngine buildValidationEngine( CliContext cliContext, String definitions, TimeTracker timeTracker) throws IOException, URISyntaxException {
protected ValidationEngine buildValidationEngine(CliContext cliContext, String definitions, TimeTracker timeTracker) throws IOException, URISyntaxException {
System.out.print(" Load FHIR v" + cliContext.getSv() + " from " + definitions);
ValidationEngine validationEngine = getValidationEngineBuilder().withTHO(false).withVersion(cliContext.getSv()).withTimeTracker(timeTracker).withUserAgent(Common.getValidatorUserAgent()).fromSource(definitions);
System.out.println(" - " + validationEngine.getContext().countAllCaches() + " resources (" + timeTracker.milestone() + ")");
loadIgsAndExtensions(validationEngine, cliContext, timeTracker);
if (validationEngine.getContext().getTxCache() == null) {
if (cliContext.getTxCache() != null) {
TerminologyCache cache = new TerminologyCache(new Object(), cliContext.getTxCache());
validationEngine.getContext().initTxCache(cache);
}
if (validationEngine.getContext().getTxCache() == null || validationEngine.getContext().getTxCache().getFolder() == null) {
System.out.println(" No Terminology Cache");
} else {
System.out.println(" Terminology Cache at "+validationEngine.getContext().getTxCache().getFolder());

View File

@ -217,6 +217,7 @@ import org.hl7.fhir.validation.instance.type.ValueSetValidator;
import org.hl7.fhir.validation.instance.utils.*;
import org.w3c.dom.Document;
/**
* Thinking of using this in a java program? Don't!
* You should use one of the wrappers instead. Either in HAPI, or use ValidationEngine
@ -1356,19 +1357,20 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
BindingStrength strength = binding.getStrength();
Extension maxVS = binding.getExtensionByUrl(ToolingExtensions.EXT_MAX_VALUESET);
checkDisp = validateBindingCodeableConcept(errors, path, element, profile, stack, bh, checkDisp, checked, cc, vsRef, valueset, strength, maxVS, true);
checkDisp = validateBindingCodeableConcept(errors, path, element, profile, stack, bh, checkDisp, checked, cc, vsRef, valueset, strength, maxVS, true, null);
// } else if (binding.hasValueSet()) {
// hint(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_CANTCHECK);
} else if (!noBindingMsgSuppressed) {
hint(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_NOSOURCE, path);
}
for (ElementDefinitionBindingAdditionalComponent ab : binding.getAdditional()) {
if (isTestableBinding(ab) && isInScope(ab)) {
StringBuilder b = new StringBuilder();
if (isTestableBinding(ab) && isInScope(ab, profile, getResource(stack), b)) {
String vsRef = ab.getValueSet();
ValueSet valueset = resolveBindingReference(profile, vsRef, profile.getUrl(), profile);
BindingStrength strength = convertPurposeToStrength(ab.getPurpose());
checkDisp = validateBindingCodeableConcept(errors, path, element, profile, stack, bh, checkDisp, checked, cc, vsRef, valueset, strength, null, false) && checkDisp;
checkDisp = validateBindingCodeableConcept(errors, path, element, profile, stack, bh, checkDisp, checked, cc, vsRef, valueset, strength, null, false, b.toString()) && checkDisp;
}
}
} catch (CheckCodeOnServerException e) {
@ -1394,25 +1396,186 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
return checkDisp;
}
private boolean isInScope(ElementDefinitionBindingAdditionalComponent ab) {
private boolean isInScope(ElementDefinitionBindingAdditionalComponent ab, StructureDefinition profile, Element resource, StringBuilder b) {
if (ab.getUsage().isEmpty()) {
return true;
}
boolean ok = true;
for (UsageContext usage : ab.getUsage()) {
if (isInScope(usage)) {
if (!isInScope(usage, profile, resource, b)) {
ok = false;
}
}
return ok;
}
private boolean isInScope(UsageContext usage, StructureDefinition profile, Element resource, StringBuilder b) {
if (isKnownUsage(usage)) {
return true;
}
if (usage.getCode().hasSystem() && (usage.getCode().getSystem().equals(profile.getUrl()) || usage.getCode().getSystem().equals(profile.getVersionedUrl()))) {
// if it's not a defined usage from external sources, it might match something in the data content
List<Element> items = findDataValue(resource, usage.getCode().getCode());
if (matchesUsage(items, usage.getValue())) {
b.append(context.formatMessage(I18nConstants.BINDING_ADDITIONAL_USAGE, displayCoding(usage.getCode()), display(usage.getValue())));
return true;
}
}
return ab.getUsage().isEmpty();
return false;
}
private boolean isInScope(UsageContext usage) {
if (isKnownUsage(usage)) {
private String displayCoding(Coding value) {
return value.getCode();
}
private String displayCodeableConcept(CodeableConcept value) {
for (Coding c : value.getCoding()) {
String s = displayCoding(c);
if (s != null) {
return s;
}
}
return value.getText();
}
private String display(DataType value) {
switch (value.fhirType()) {
case "Coding" : return displayCoding((Coding) value);
case "CodeableConcept" : return displayCodeableConcept((CodeableConcept) value);
}
return value.fhirType();
}
private boolean matchesUsage(List<Element> items, DataType value) {
for (Element item : items) {
if (matchesUsage(item, value)) {
return true;
}
}
return false;
}
private String display(List<Element> items) {
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
for (Element item : items) {
display(b, item);
}
return b.toString();
}
private void display(CommaSeparatedStringBuilder b, Element item) {
if (item.isPrimitive()) {
b.append(item.primitiveValue());
} else if (item.fhirType().equals("CodeableConcept")) {
for (Element c : item.getChildren("coding")) {
b.append(c.getNamedChildValue("code"));
}
} else {
b.append(item.toString());
}
}
private boolean matchesUsage(Element item, DataType value) {
switch (value.fhirType()) {
case "CodeableConcept": return matchesUsageCodeableConcept(item, (CodeableConcept) value);
case "Quantity": return false;
case "Range": return false;
case "Reference": return false;
default: return false;
}
}
private boolean matchesUsageCodeableConcept(Element item, CodeableConcept value) {
switch (item.fhirType()) {
case "CodeableConcept": return matchesUsageCodeableConceptCodeableConcept(item, value);
case "Coding": return matchesUsageCodeableConceptCoding(item, value);
default: return false;
}
}
private boolean matchesUsageCodeableConceptCoding(Element item, CodeableConcept value) {
String system = item.getNamedChildValue("system");
String version = item.getNamedChildValue("version");
String code = item.getNamedChildValue("code");
for (Coding c : value.getCoding()) {
if (system == null || !system.equals(c.getSystem())) {
return false;
}
if (code == null || !code.equals(c.getCode())) {
return false;
}
if (c.hasVersion()) {
if (version == null || !version.equals(c.getVersion())) {
return false;
}
}
return true;
}
return false;
}
private boolean matchesUsageCodeableConceptCodeableConcept(Element item, CodeableConcept value) {
for (Element code : item.getChildren("coding")) {
if (matchesUsageCodeableConceptCoding(code, value)) {
return true;
}
}
return false;
}
private List<Element> findDataValue(Element resource, String code) {
List<Element> items = new ArrayList<Element>();
if (resource != null) {
findDataValues(items, resource, code);
}
return items;
}
private void findDataValues(List<Element> items, Element element, String path) {
if (element.getPath() == null) {
return;
}
if (pathMatches(element.getPath(), path)) {
items.add(element);
} else if (element.hasChildren() && path.startsWith(element.getPath())) {
for (Element child : element.getChildren()) {
findDataValues(items, child, path);
}
}
}
private boolean pathMatches(String actualPath, String pathSpec) {
String[] ap = actualPath.split("\\.");
String[] ps = pathSpec.split("\\.");
if (ap.length != ps.length) {
return false;
}
for (int i = 0; i < ap.length; i++) {
if (!pathSegmentMatches(ap[i], ps[i])) {
return false;
}
}
return true;
}
private boolean pathSegmentMatches(String ap, String ps) {
if (ps.contains("[")) {
return ap.equals(ps);
} else {
if (ap.contains("[")) {
ap = ap.substring(0, ap.indexOf("["));
}
return ap.equals(ps);
}
}
private BindingStrength convertPurposeToStrength(AdditionalBindingPurposeVS purpose) {
switch (purpose) {
case MAXIMUM: return BindingStrength.REQUIRED;
case EXTENSIBLE: return BindingStrength.EXTENSIBLE;
case PREFERRED: return BindingStrength.PREFERRED;
case REQUIRED: return BindingStrength.REQUIRED;
default: return null;
@ -1424,7 +1587,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
private boolean validateBindingCodeableConcept(List<ValidationMessage> errors, String path, Element element, StructureDefinition profile, NodeStack stack, BooleanHolder bh, boolean checkDisp, BooleanHolder checked,
CodeableConcept cc, String vsRef, ValueSet valueset, BindingStrength strength, Extension maxVS, boolean base) throws CheckCodeOnServerException {
CodeableConcept cc, String vsRef, ValueSet valueset, BindingStrength strength, Extension maxVS, boolean base, String usageNote) throws CheckCodeOnServerException {
if (valueset == null) {
CodeSystem cs = context.fetchCodeSystem(vsRef);
if (rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, cs == null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND_CS, describeReference(vsRef))) {
@ -1436,12 +1599,12 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
BindingContext bc = base ? BindingContext.BASE : BindingContext.ADDITIONAL;
if (!cc.hasCoding()) {
if (strength == BindingStrength.REQUIRED)
bh.see(rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CODE_VALUESET, describeReference(vsRef, valueset, bc)));
bh.see(rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CODE_VALUESET, describeReference(vsRef, valueset, bc, usageNote)));
else if (strength == BindingStrength.EXTENSIBLE) {
if (maxVS != null)
bh.see(rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CODE_VALUESETMAX, describeReference(ToolingExtensions.readStringFromExtension(maxVS)), valueset.getVersionedUrl()));
else if (!noExtensibleWarnings) {
warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CODE_VALUESET_EXT, describeReference(vsRef, valueset, bc));
warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CODE_VALUESET_EXT, describeReference(vsRef, valueset, bc, usageNote));
}
}
} else {
@ -1491,17 +1654,17 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
} else if (vr.getErrorClass() != null && vr.getErrorClass() == TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED) {
// we've already handled the warnings / errors about this, and set the status correctly. We don't need to do anything more?
} else {
} else if (vr.getErrorClass() != TerminologyServiceErrorClass.SERVER_ERROR) { // (should have?) already handled server error
if (strength == BindingStrength.REQUIRED) {
bh.see(txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_1_CC, describeReference(vsRef, valueset, bc), ccSummary(cc)));
bh.see(txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_1_CC, describeReference(vsRef, valueset, bc, usageNote), ccSummary(cc)));
} else if (strength == BindingStrength.EXTENSIBLE) {
if (maxVS != null)
bh.see(checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringFromExtension(maxVS), cc, stack));
if (!noExtensibleWarnings)
txWarningForLaterRemoval(element, errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_2_CC, describeReference(vsRef, valueset, bc), ccSummary(cc));
txWarningForLaterRemoval(element, errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_2_CC, describeReference(vsRef, valueset, bc, usageNote), ccSummary(cc));
} else if (strength == BindingStrength.PREFERRED) {
if (baseOnly) {
txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_3_CC, describeReference(vsRef, valueset, bc), ccSummary(cc));
txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_3_CC, describeReference(vsRef, valueset, bc, usageNote), ccSummary(cc));
}
}
}
@ -1648,7 +1811,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
BindingStrength strength = binding.getStrength();
Extension vsMax = binding.getExtensionByUrl(ToolingExtensions.EXT_MAX_VALUESET);
validateBindingCodeableConcept(errors, path, element, profile, stack, ok, false, new BooleanHolder(), cc, vsRef, valueset, strength, vsMax, true);
validateBindingCodeableConcept(errors, path, element, profile, stack, ok, false, new BooleanHolder(), cc, vsRef, valueset, strength, vsMax, true, null);
// special case: if the logical model has both CodeableConcept and Coding mappings, we'll also check the first coding.
if (getMapping("http://hl7.org/fhir/terminology-pattern", logical, logical.getSnapshot().getElementFirstRep()).contains("Coding")) {
@ -1660,11 +1823,12 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
hint(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_NOSOURCE, path);
}
for (ElementDefinitionBindingAdditionalComponent ab : binding.getAdditional()) {
if (isTestableBinding(ab) && isInScope(ab)) {
StringBuilder b = new StringBuilder();
if (isTestableBinding(ab) && isInScope(ab, profile, getResource(stack), b)) {
String vsRef = ab.getValueSet();
ValueSet valueset = resolveBindingReference(profile, vsRef, profile.getUrl(), profile);
BindingStrength strength = convertPurposeToStrength(ab.getPurpose());
validateBindingCodeableConcept(errors, path, element, profile, stack, ok, false, new BooleanHolder(), cc, vsRef, valueset, strength, null, false);
validateBindingCodeableConcept(errors, path, element, profile, stack, ok, false, new BooleanHolder(), cc, vsRef, valueset, strength, null, false, b.toString());
}
}
}
@ -1698,18 +1862,19 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
BindingStrength strength = binding.getStrength();
Extension vsMax = binding.getExtensionByUrl(ToolingExtensions.EXT_MAX_VALUESET);
ok = validateBindingTerminologyCoding(errors, path, element, profile, stack, ok, c, code, system, display, vsRef, valueset, strength, vsMax, true);
ok = validateBindingTerminologyCoding(errors, path, element, profile, stack, ok, c, code, system, display, vsRef, valueset, strength, vsMax, true, null);
} else if (binding.hasValueSet()) {
hint(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_CANTCHECK);
} else if (!inCodeableConcept && !noBindingMsgSuppressed) {
hint(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_NOSOURCE, path);
}
for (ElementDefinitionBindingAdditionalComponent ab : binding.getAdditional()) {
if (isTestableBinding(ab) && isInScope(ab)) {
StringBuilder b = new StringBuilder();
if (isTestableBinding(ab) && isInScope(ab, profile, getResource(stack), b)) {
String vsRef = ab.getValueSet();
ValueSet valueset = resolveBindingReference(profile, vsRef, profile.getUrl(), profile);
BindingStrength strength = convertPurposeToStrength(ab.getPurpose());
ok = validateBindingTerminologyCoding(errors, path, element, profile, stack, ok, c, code, system, display, vsRef, valueset, strength, null, true) && ok;
ok = validateBindingTerminologyCoding(errors, path, element, profile, stack, ok, c, code, system, display, vsRef, valueset, strength, null, true, b.toString()) && ok;
}
}
}
@ -1728,7 +1893,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private boolean validateBindingTerminologyCoding(List<ValidationMessage> errors, String path, Element element,
StructureDefinition profile, NodeStack stack, boolean ok, Coding c, String code, String system, String display,
String vsRef, ValueSet valueset, BindingStrength strength, Extension vsMax, boolean base) {
String vsRef, ValueSet valueset, BindingStrength strength, Extension vsMax, boolean base, String usageNote) {
if (valueset == null) {
CodeSystem cs = context.fetchCodeSystem(vsRef);
if (rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, cs == null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND_CS, describeReference(vsRef))) {
@ -1754,27 +1919,27 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_NOSERVER, system+"#"+code);
else if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure()) {
if (strength == BindingStrength.REQUIRED)
txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_4a, describeReference(vsRef, valueset, bc), vr.getMessage(), system+"#"+code);
txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_4a, describeReference(vsRef, valueset, bc, usageNote), vr.getMessage(), system+"#"+code);
else if (strength == BindingStrength.EXTENSIBLE) {
if (vsMax != null)
checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringFromExtension(vsMax), c, stack);
else if (!noExtensibleWarnings)
txWarningForLaterRemoval(element, errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_5, describeReference(vsRef, valueset, bc));
txWarningForLaterRemoval(element, errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_5, describeReference(vsRef, valueset, bc, usageNote));
} else if (strength == BindingStrength.PREFERRED) {
if (baseOnly) {
txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_6, describeReference(vsRef, valueset, bc));
txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_6, describeReference(vsRef, valueset, bc, usageNote));
}
}
} else if (strength == BindingStrength.REQUIRED)
ok= txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_4, describeReference(vsRef, valueset, bc), (vr.getMessage() != null ? " (error message = " + vr.getMessage() + ")" : ""), system+"#"+code) && ok;
ok= txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_4, describeReference(vsRef, valueset, bc, usageNote), (vr.getMessage() != null ? " (error message = " + vr.getMessage() + ")" : ""), system+"#"+code) && ok;
else if (strength == BindingStrength.EXTENSIBLE) {
if (vsMax != null)
ok = checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringFromExtension(vsMax), c, stack) && ok;
else
txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_5, describeReference(vsRef, valueset, bc), (vr.getMessage() != null ? " (error message = " + vr.getMessage() + ")" : ""), system+"#"+code);
txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_5, describeReference(vsRef, valueset, bc, usageNote), (vr.getMessage() != null ? " (error message = " + vr.getMessage() + ")" : ""), system+"#"+code);
} else if (strength == BindingStrength.PREFERRED) {
if (baseOnly) {
txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_6, describeReference(vsRef, valueset, bc), (vr.getMessage() != null ? " (error message = " + vr.getMessage() + ")" : ""), system+"#"+code);
txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_6, describeReference(vsRef, valueset, bc, usageNote), (vr.getMessage() != null ? " (error message = " + vr.getMessage() + ")" : ""), system+"#"+code);
}
}
} else if (vr != null && vr.getMessage() != null){
@ -1896,9 +2061,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
timeTracker.tx(t, "vc "+cc.toString());
if (!vr.isOk()) {
if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure())
txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_7, describeReference(maxVSUrl, valueset, BindingContext.MAXVS), vr.getMessage());
txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_7, describeReference(maxVSUrl, valueset, BindingContext.MAXVS, null), vr.getMessage());
else
ok = txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_8, describeReference(maxVSUrl, valueset, BindingContext.MAXVS), ccSummary(cc)) && ok;
ok = txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_8, describeReference(maxVSUrl, valueset, BindingContext.MAXVS, null), ccSummary(cc)) && ok;
}
} catch (CheckCodeOnServerException e) {
if (STACK_TRACE) e.getCause().printStackTrace();
@ -1936,9 +2101,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
timeTracker.tx(t, "vc "+c.getSystem()+"#"+c.getCode()+" '"+c.getDisplay()+"'");
if (!vr.isOk()) {
if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure())
txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_9, describeReference(maxVSUrl, valueset, BindingContext.MAXVS), vr.getMessage(), c.getSystem()+"#"+c.getCode());
txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_9, describeReference(maxVSUrl, valueset, BindingContext.MAXVS, null), vr.getMessage(), c.getSystem()+"#"+c.getCode());
else
ok = txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_10, describeReference(maxVSUrl, valueset, BindingContext.MAXVS), c.getSystem(), c.getCode()) && ok;
ok = txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_10, describeReference(maxVSUrl, valueset, BindingContext.MAXVS, null), c.getSystem(), c.getCode()) && ok;
}
} catch (Exception e) {
if (STACK_TRACE) e.printStackTrace();
@ -1966,9 +2131,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
timeTracker.tx(t, "vc "+value);
if (!vr.isOk()) {
if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure())
txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_9, describeReference(maxVSUrl, valueset, BindingContext.BASE), vr.getMessage(), value);
txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_9, describeReference(maxVSUrl, valueset, BindingContext.BASE, null), vr.getMessage(), value);
else {
ok = txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_11, describeReference(maxVSUrl, valueset, BindingContext.BASE), vr.getMessage()) && ok;
ok = txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_11, describeReference(maxVSUrl, valueset, BindingContext.BASE, null), vr.getMessage()) && ok;
}
}
} catch (Exception e) {
@ -2029,7 +2194,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
BindingStrength strength = binding.getStrength();
Extension vsMax = binding.getExtensionByUrl(ToolingExtensions.EXT_MAX_VALUESET);
ok = validateBindingCodedElement(errors, path, element, profile, stack, theCode, theSystem, ok, checked, c, vsRef, valueset, strength, vsMax, true);
ok = validateBindingCodedElement(errors, path, element, profile, stack, theCode, theSystem, ok, checked, c, vsRef, valueset, strength, vsMax, true, null);
// } else if (binding.hasValueSet()) {
// hint(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_CANTCHECK);
@ -2038,12 +2203,13 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
for (ElementDefinitionBindingAdditionalComponent ab : binding.getAdditional()) {
if (isTestableBinding(ab) && isInScope(ab)) {
StringBuilder b = new StringBuilder();
if (isTestableBinding(ab) && isInScope(ab, profile, getResource(stack), b)) {
String vsRef = ab.getValueSet();
ValueSet valueset = resolveBindingReference(profile, vsRef, profile.getUrl(), profile);
BindingStrength strength = convertPurposeToStrength(ab.getPurpose());
ok = validateBindingCodedElement(errors, path, element, profile, stack, theCode, theSystem, ok, checked, c, vsRef, valueset, strength, null, false) && ok;
ok = validateBindingCodedElement(errors, path, element, profile, stack, theCode, theSystem, ok, checked, c, vsRef, valueset, strength, null, false, b.toString()) && ok;
}
}
} catch (Exception e) {
@ -2068,9 +2234,19 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
return ok;
}
private Element getResource(NodeStack stack) {
if (stack.getElement().isResource()) {
return stack.getElement();
}
if (stack.getParent() == null) {
return null;
}
return getResource(stack.getParent());
}
private boolean validateBindingCodedElement(List<ValidationMessage> errors, String path, Element element,
StructureDefinition profile, NodeStack stack, String theCode, String theSystem, boolean ok, BooleanHolder checked,
Coding c, String vsRef, ValueSet valueset, BindingStrength strength, Extension vsMax, boolean base) {
Coding c, String vsRef, ValueSet valueset, BindingStrength strength, Extension vsMax, boolean base, String usageNote) {
if (valueset == null) {
CodeSystem cs = context.fetchCodeSystem(vsRef);
if (rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, cs == null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND_CS, describeReference(vsRef))) {
@ -2098,28 +2274,28 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_NOSERVER, theSystem+"#"+theCode);
else if (vr.getErrorClass() != null && !vr.getErrorClass().isInfrastructure()) {
if (strength == BindingStrength.REQUIRED)
ok = txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_4a, describeReference(vsRef, valueset, bc), vr.getMessage(), theSystem+"#"+theCode) && ok;
ok = txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_4a, describeReference(vsRef, valueset, bc, usageNote), vr.getMessage(), theSystem+"#"+theCode) && ok;
else if (strength == BindingStrength.EXTENSIBLE) {
if (vsMax != null)
checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringFromExtension(vsMax), c, stack);
else if (!noExtensibleWarnings)
txWarningForLaterRemoval(element, errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_5, describeReference(vsRef, valueset, bc), theSystem+"#"+theCode);
txWarningForLaterRemoval(element, errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_5, describeReference(vsRef, valueset, bc, usageNote), theSystem+"#"+theCode);
} else if (strength == BindingStrength.PREFERRED) {
if (baseOnly) {
txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_6, describeReference(vsRef, valueset, bc), theSystem+"#"+theCode);
txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_6, describeReference(vsRef, valueset, bc, usageNote), theSystem+"#"+theCode);
}
}
} else if (strength == BindingStrength.REQUIRED)
ok = txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_12, describeReference(vsRef, valueset, bc), getErrorMessage(vr.getMessage()), theSystem+"#"+theCode) && ok;
ok = txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_12, describeReference(vsRef, valueset, bc, usageNote), getErrorMessage(vr.getMessage()), theSystem+"#"+theCode) && ok;
else if (strength == BindingStrength.EXTENSIBLE) {
if (vsMax != null)
ok = checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringFromExtension(vsMax), c, stack) && ok;
else if (!noExtensibleWarnings) {
txWarningForLaterRemoval(element, errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_13, describeReference(vsRef, valueset, bc), getErrorMessage(vr.getMessage()), c.getSystem()+"#"+c.getCode());
txWarningForLaterRemoval(element, errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_13, describeReference(vsRef, valueset, bc, usageNote), getErrorMessage(vr.getMessage()), c.getSystem()+"#"+c.getCode());
}
} else if (strength == BindingStrength.PREFERRED) {
if (baseOnly) {
txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_14, describeReference(vsRef, valueset, bc), getErrorMessage(vr.getMessage()), theSystem+"#"+theCode);
txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_14, describeReference(vsRef, valueset, bc, usageNote), getErrorMessage(vr.getMessage()), theSystem+"#"+theCode);
}
}
} else if (vr != null && vr.getMessage() != null) {
@ -3017,7 +3193,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
// check that no illegal elements and attributes have been used
ok = checkInnerNames(errors, e, path, xhtml.getChildNodes(), false) && ok;
ok = checkUrls(errors, e, path, xhtml.getChildNodes()) && ok;
ok = checkIdRefs(errors, e, path, xhtml, resource) && ok;
ok = checkIdRefs(errors, e, path, xhtml, resource, node) && ok;
if (true) {
ok = checkReferences(valContext, errors, e, path, "div", xhtml, resource) && ok;
}
@ -3466,11 +3642,11 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
return ok;
}
private boolean checkIdRefs(List<ValidationMessage> errors, Element e, String path, XhtmlNode node, Element resource) {
private boolean checkIdRefs(List<ValidationMessage> errors, Element e, String path, XhtmlNode node, Element resource, NodeStack stack) {
boolean ok = true;
if (node.getNodeType() == NodeType.Element && node.getAttribute("idref") != null) {
String idref = node.getAttribute("idref");
int count = countFragmentMatches(resource, idref);
int count = countFragmentMatches(resource, idref, stack);
if (count == 0) {
ok = warning(errors, "2023-12-01", IssueType.INVALID, e.line(), e.col(), path, idref == null, I18nConstants.XHTML_IDREF_NOT_FOUND, idref) && ok;
} else if (count > 1) {
@ -3479,7 +3655,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
if (node.hasChildren()) {
for (XhtmlNode child : node.getChildNodes()) {
checkIdRefs(errors, e, path, child, resource);
checkIdRefs(errors, e, path, child, resource, stack);
}
}
return ok;
@ -3563,15 +3739,15 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
} else if (vr.getErrorClass() != null && vr.getErrorClass() == TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED) {
txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, vr.getMessage());
} else if (binding.getStrength() == BindingStrength.REQUIRED) {
ok = txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_16, value, describeReference(binding.getValueSet(), vs, BindingContext.BASE), getErrorMessage(vr.getMessage())) && ok;
ok = txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_16, value, describeReference(binding.getValueSet(), vs, BindingContext.BASE, null), getErrorMessage(vr.getMessage())) && ok;
} else if (binding.getStrength() == BindingStrength.EXTENSIBLE) {
if (binding.hasExtension(ToolingExtensions.EXT_MAX_VALUESET))
ok = checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, ToolingExtensions.EXT_MAX_VALUESET), value, stack) && ok;
else if (!noExtensibleWarnings && !isOkExtension(value, vs))
txWarningForLaterRemoval(element, errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_17, value, describeReference(binding.getValueSet(), vs, BindingContext.BASE), getErrorMessage(vr.getMessage()));
txWarningForLaterRemoval(element, errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_17, value, describeReference(binding.getValueSet(), vs, BindingContext.BASE, null), getErrorMessage(vr.getMessage()));
} else if (binding.getStrength() == BindingStrength.PREFERRED) {
if (baseOnly) {
txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_18, value, describeReference(binding.getValueSet(), vs, BindingContext.BASE), getErrorMessage(vr.getMessage()));
txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_18, value, describeReference(binding.getValueSet(), vs, BindingContext.BASE, null), getErrorMessage(vr.getMessage()));
}
}
} else if (vr != null && vr.getMessage() != null){
@ -4279,7 +4455,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
return false;
}
private String describeReference(String reference, CanonicalResource target, BindingContext ctxt) {
private String describeReference(String reference, CanonicalResource target, BindingContext ctxt, String usageNote) {
if (reference == null && target == null)
return "null";
String res = null;
@ -4297,7 +4473,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
}
switch (ctxt) {
case ADDITIONAL: return context.formatMessage(I18nConstants.BINDING_ADDITIONAL, res);
case ADDITIONAL: return context.formatMessage(Utilities.noString(usageNote) ? I18nConstants.BINDING_ADDITIONAL_D : I18nConstants.BINDING_ADDITIONAL_UC, res, usageNote);
case MAXVS: return context.formatMessage(I18nConstants.BINDING_MAX, res);
default: return res;
}
@ -5891,20 +6067,22 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
Element div = text.getNamedChild("div", false);
if (lang != null && div != null) {
XhtmlNode xhtml = div.getXhtml();
String l = xhtml.getAttribute("lang");
String xl = xhtml.getAttribute("xml:lang");
if (l == null && xl == null) {
warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, div.line(), div.col(), stack.getLiteralPath(), false, I18nConstants.LANGUAGE_XHTML_LANG_MISSING1);
} else {
if (l == null) {
warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, div.line(), div.col(), stack.getLiteralPath(), false, I18nConstants.LANGUAGE_XHTML_LANG_MISSING2);
} else if (!l.equals(lang)) {
warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, div.line(), div.col(), stack.getLiteralPath(), false, I18nConstants.LANGUAGE_XHTML_LANG_DIFFERENT1, lang, l);
}
if (xl == null) {
warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, div.line(), div.col(), stack.getLiteralPath(), false, I18nConstants.LANGUAGE_XHTML_LANG_MISSING3);
} else if (!xl.equals(lang)) {
warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, div.line(), div.col(), stack.getLiteralPath(), false, I18nConstants.LANGUAGE_XHTML_LANG_DIFFERENT2, lang, xl);
if (xhtml != null) {
String l = xhtml.getAttribute("lang");
String xl = xhtml.getAttribute("xml:lang");
if (l == null && xl == null) {
warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, div.line(), div.col(), stack.getLiteralPath(), false, I18nConstants.LANGUAGE_XHTML_LANG_MISSING1);
} else {
if (l == null) {
warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, div.line(), div.col(), stack.getLiteralPath(), false, I18nConstants.LANGUAGE_XHTML_LANG_MISSING2);
} else if (!l.equals(lang)) {
warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, div.line(), div.col(), stack.getLiteralPath(), false, I18nConstants.LANGUAGE_XHTML_LANG_DIFFERENT1, lang, l);
}
if (xl == null) {
warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, div.line(), div.col(), stack.getLiteralPath(), false, I18nConstants.LANGUAGE_XHTML_LANG_MISSING3);
} else if (!xl.equals(lang)) {
warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, div.line(), div.col(), stack.getLiteralPath(), false, I18nConstants.LANGUAGE_XHTML_LANG_DIFFERENT2, lang, xl);
}
}
}
}
@ -7439,6 +7617,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
public long timeNoTX() {
return (timeTracker.getOverall() - timeTracker.getTxTime()) / 1000000;
}
public String reportTimes() {
String s = String.format("Times (ms): overall = %d:4, tx = %d, sd = %d, load = %d, fpe = %d, spec = %d", timeTracker.getOverall() / 1000000, timeTracker.getTxTime() / 1000000, timeTracker.getSdTime() / 1000000, timeTracker.getLoadTime() / 1000000, timeTracker.getFpeTime() / 1000000, timeTracker.getSpecTime() / 1000000);
timeTracker.reset();
@ -7852,6 +8033,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
public void setNoExperimentalContent(boolean noExperimentalContent) {
this.noExperimentalContent = noExperimentalContent;
}
public void resetTimes() {
timeTracker.reset();
}
}

View File

@ -191,7 +191,7 @@ public class StructureDefinitionValidator extends BaseValidator {
}
}
} catch (Exception e) {
e.printStackTrace();
//e.printStackTrace();
rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.getLiteralPath(), false, I18nConstants.ERROR_GENERATING_SNAPSHOT, e.getMessage());
ok = false;
}
@ -525,7 +525,7 @@ public class StructureDefinitionValidator extends BaseValidator {
ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), characteristics.contains("can-bind") , I18nConstants.SD_ILLEGAL_CHARACTERISTICS, "Binding", typeCodes) && ok;
}
Element binding = element.getNamedChild("binding", false);
ok = validateBinding(errors, binding, stack.push(binding, -1, null, null), typeCodes, snapshot, path, experimental) && ok;
ok = validateBinding(errors, binding, stack.push(binding, -1, null, null), typeCodes, snapshot, path, experimental, sd) && ok;
} else {
// this is a good idea but there's plenty of cases where the rule isn't met; maybe one day it's worth investing the time to exclude these cases and bring this rule back
// String bt = boundType(typeCodes);
@ -989,7 +989,7 @@ public class StructureDefinitionValidator extends BaseValidator {
return null;
}
private boolean validateBinding(List<ValidationMessage> errors, Element binding, NodeStack stack, Set<String> typeCodes, boolean snapshot, String path, boolean experimental) {
private boolean validateBinding(List<ValidationMessage> errors, Element binding, NodeStack stack, Set<String> typeCodes, boolean snapshot, String path, boolean experimental, StructureDefinition profile) {
boolean ok = true;
if (bindableType(typeCodes) == null) {
ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), !snapshot, I18nConstants.SD_ED_BIND_NO_BINDABLE, path, typeCodes.toString()) && ok;
@ -1019,9 +1019,122 @@ public class StructureDefinitionValidator extends BaseValidator {
}
}
}
if (binding.hasChildren("additional")) {
int i = 0;
for (Element ab : binding.getChildren("additional")) {
ok = validateAdditionalBinding(errors, ab, stack.push(ab, i, null, null), snapshot, path, experimental) && ok;
i++;
}
}
if (binding.hasExtension(ToolingExtensions.EXT_BINDING_ADDITIONAL)) {
int i = 0;
for (Element ab : binding.getChildren("extension")) {
String url = ab.getNamedChildValue("url");
if (ToolingExtensions.EXT_BINDING_ADDITIONAL.equals(url)) {
ok = validateAdditionalBindingExtension(errors, ab, stack.push(ab, i, null, null), snapshot, path, experimental, profile) && ok;
}
i++;
}
}
return ok;
}
private boolean validateAdditionalBinding(List<ValidationMessage> errors, Element binding, NodeStack stack, boolean snapshot, String path, boolean experimental) {
boolean ok = true;
if (binding.hasChild("valueSet", false)) {
Element valueSet = binding.getNamedChild("valueSet", false);
String ref = valueSet.hasPrimitiveValue() ? valueSet.primitiveValue() : valueSet.getNamedChildValue("reference", false);
if (warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), !snapshot || ref != null, I18nConstants.SD_ED_SHOULD_BIND_WITH_VS, path)) {
Resource vs = context.fetchResource(Resource.class, ref);
// just because we can't resolve it directly doesn't mean that terminology server can't. Check with it
if (warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), vs != null || serverSupportsValueSet(ref), I18nConstants.SD_ED_BIND_UNKNOWN_VS, path, ref)) {
if (vs != null) {
if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), vs instanceof ValueSet, I18nConstants.SD_ED_BIND_NOT_VS, path, ref, vs.fhirType())) {
ValueSet vsr = (ValueSet) vs;
warning(errors, "2024-09-17", IssueType.BUSINESSRULE, stack.getLiteralPath(), !vsr.getExperimental() || experimental, I18nConstants.SD_ED_EXPERIMENTAL_BINDING, path, ref);
} else {
ok = false;
}
}
}
}
}
if (binding.hasChildren("usage")) {
for (Element usage : binding.getChildren("usage")) {
warning(errors, "2024-09-20", IssueType.BUSINESSRULE, stack.getLiteralPath(), false, "test");
}
}
return ok;
}
private boolean validateAdditionalBindingExtension(List<ValidationMessage> errors, Element binding, NodeStack stack, boolean snapshot, String path, boolean experimental, StructureDefinition profile) {
boolean ok = true;
if (binding.hasExtension("valueSet")) {
Element valueSet = binding.getExtension("valueSet");
Element vv = valueSet.getNamedChild("value");
String ref = vv.hasPrimitiveValue() ? vv.primitiveValue() : vv.getNamedChildValue("reference", false);
if (warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), !snapshot || ref != null, I18nConstants.SD_ED_SHOULD_BIND_WITH_VS, path)) {
Resource vs = context.fetchResource(Resource.class, ref);
// just because we can't resolve it directly doesn't mean that terminology server can't. Check with it
if (warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), vs != null || serverSupportsValueSet(ref), I18nConstants.SD_ED_BIND_UNKNOWN_VS, path, ref)) {
if (vs != null) {
if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), vs instanceof ValueSet, I18nConstants.SD_ED_BIND_NOT_VS, path, ref, vs.fhirType())) {
ValueSet vsr = (ValueSet) vs;
warning(errors, "2024-09-17", IssueType.BUSINESSRULE, stack.getLiteralPath(), !vsr.getExperimental() || experimental, I18nConstants.SD_ED_EXPERIMENTAL_BINDING, path, ref);
} else {
ok = false;
}
}
}
}
}
if (binding.hasExtension("usage")) {
int i = 0;
for (Element usage : binding.getChildren("extension")) {
String url = usage.getNamedChildValue("url");
if ("usage".equals(url)) {
Element uv = usage.getNamedChild("value");
ok = validateAdditionalBindingUsage(errors, uv, stack.push(uv, -1, null, null), path, profile) && ok;
}
i++;
}
}
return ok;
}
private boolean validateAdditionalBindingUsage(List<ValidationMessage> errors, Element usage, NodeStack stack, String path, StructureDefinition profile) {
boolean ok = true;
Element cc = usage.getNamedChild("code");
if (cc != null) {
String system = cc.getNamedChildValue("system");
String code = cc.getNamedChildValue("code");
if (system != null && system.equals(profile.getUrl())) {
ElementDefinition ed = profile.getDifferential().getElementByPath(code);
if (ed == null) {
ed = profile.getSnapshot().getElementByPath(code);
}
if (ed == null) {
ok = false;
rule(errors, "2024-09-17", IssueType.BUSINESSRULE, stack.getLiteralPath(), false, I18nConstants.SD_ED_ADDITIONAL_BINDING_USAGE_INVALID_ELEMENT, system, code);
} else {
if (usage.hasChild("value")) {
String t = usage.getNamedChild("value").fhirType();
ok = rule(errors, "2024-09-20", IssueType.BUSINESSRULE, stack.getLiteralPath(), "CodeableConcept".equals(t), I18nConstants.SD_ED_ADDITIONAL_BINDING_USAGE_INVALID_TYPE, t, "CodeableConcept") && ok;
}
}
} else {
warning(errors, "2024-09-17", IssueType.BUSINESSRULE, stack.getLiteralPath(), false, I18nConstants.SD_ED_ADDITIONAL_BINDING_USAGE_UNKNOWN, system, code);
}
}
return ok;
}
private Set<String> getListofBindableTypes(Set<String> types) {
Set<String> res = new HashSet<>();
for (String s : types) {

View File

@ -1,3 +1,4 @@
[servers]
tx-dev.fhir.org.r2 = http://tx-dev.fhir.org/r2
local.fhir.org.r2 = http://local.fhir.org/r2

View File

@ -1,3 +1,4 @@
[servers]
tx-dev.fhir.org.r3 = http://tx-dev.fhir.org/r3
local.fhir.org.r3 = http://local.fhir.org/r3

View File

@ -521,7 +521,6 @@ v: {
"system" : "http://unitsofmeasure.org",
"version" : "2.0.1",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -549,7 +548,6 @@ v: {
"code" : "image/jpg",
"system" : "urn:ietf:bcp:13",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -577,7 +575,6 @@ v: {
"code" : "image/jpg",
"system" : "urn:ietf:bcp:13",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -605,7 +602,6 @@ v: {
"code" : "application/pdf",
"system" : "urn:ietf:bcp:13",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -633,7 +629,6 @@ v: {
"code" : "application/pdf",
"system" : "urn:ietf:bcp:13",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -654,7 +649,6 @@ v: {
"code" : "de-CH",
"system" : "urn:ietf:bcp:47",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -720,3 +714,29 @@ v: {
}
-------------------------------------------------------------------------------------
{"code" : {
"coding" : [{
"system" : "urn:iso:std:iso:3166",
"code" : "US",
"display" : "United States of America"
}]
}, "url": "http://hl7.org/fhir/ValueSet/jurisdiction", "version": "3.0.2", "langs":"en-US", "useServer":"true", "useClient":"true", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"display" : "United States of America",
"code" : "US",
"system" : "urn:iso:std:iso:3166",
"version" : "2018",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
}
-------------------------------------------------------------------------------------

View File

@ -1,3 +1,4 @@
[servers]
tx-dev.fhir.org.r3 = http://tx-dev.fhir.org/r3
local.fhir.org.r3 = http://local.fhir.org/r3

View File

@ -1108,7 +1108,6 @@ v: {
"system" : "http://snomed.info/sct",
"version" : "http://snomed.info/sct/900000000000207008/version/20240201",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -1132,7 +1131,6 @@ v: {
"system" : "http://snomed.info/sct",
"version" : "http://snomed.info/sct/900000000000207008/version/20240201",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -1159,7 +1157,6 @@ v: {
"error" : "Wrong Display Name 'Laboratory test finding (finding)' for http://snomed.info/sct#118246004. Valid display is one of 4 choices: 'Laboratory test finding', 'Laboratory test observations', 'Laboratory test result' or 'Laboratory test finding (navigational concept)' (for the language(s) 'en-US')",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -1203,7 +1200,6 @@ v: {
"error" : "Wrong Display Name 'Chemistry' for http://snomed.info/sct#275711006. Valid display is one of 2 choices: 'Serum chemistry test' or 'Serum chemistry test (procedure)' (for the language(s) 'en-US')",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -1244,7 +1240,6 @@ v: {
"system" : "http://snomed.info/sct",
"version" : "http://snomed.info/sct/900000000000207008/version/20240201",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -1268,7 +1263,6 @@ v: {
"system" : "http://snomed.info/sct",
"version" : "http://snomed.info/sct/900000000000207008/version/20240201",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -1292,7 +1286,6 @@ v: {
"system" : "http://snomed.info/sct",
"version" : "http://snomed.info/sct/900000000000207008/version/20240201",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -1316,7 +1309,6 @@ v: {
"system" : "http://snomed.info/sct",
"version" : "http://snomed.info/sct/900000000000207008/version/20240201",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -1340,7 +1332,6 @@ v: {
"system" : "http://snomed.info/sct",
"version" : "http://snomed.info/sct/900000000000207008/version/20240201",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -1364,7 +1355,6 @@ v: {
"system" : "http://snomed.info/sct",
"version" : "http://snomed.info/sct/900000000000207008/version/20240201",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -1388,7 +1378,6 @@ v: {
"system" : "http://snomed.info/sct",
"version" : "http://snomed.info/sct/900000000000207008/version/20240201",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -1413,7 +1402,6 @@ v: {
"error" : "Unknown code '823681000000100' in the CodeSystem 'http://snomed.info/sct' version 'http://snomed.info/sct/900000000000207008/version/20240201'",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -1455,7 +1443,6 @@ v: {
"error" : "Unknown code '886921000000105' in the CodeSystem 'http://snomed.info/sct' version 'http://snomed.info/sct/900000000000207008/version/20240201'",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -1497,7 +1484,6 @@ v: {
"error" : "Unknown code '1077881000000105' in the CodeSystem 'http://snomed.info/sct' version 'http://snomed.info/sct/900000000000207008/version/20240201'",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -1539,7 +1525,6 @@ v: {
"error" : "Unknown code '887181000000106' in the CodeSystem 'http://snomed.info/sct' version 'http://snomed.info/sct/900000000000207008/version/20240201'",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -1581,7 +1566,6 @@ v: {
"error" : "Unknown code '887161000000102' in the CodeSystem 'http://snomed.info/sct' version 'http://snomed.info/sct/900000000000207008/version/20240201'",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -1623,7 +1607,6 @@ v: {
"error" : "Unknown code '1052891000000108' in the CodeSystem 'http://snomed.info/sct' version 'http://snomed.info/sct/900000000000207008/version/20240201'",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -1665,7 +1648,6 @@ v: {
"error" : "Unknown code '715851000000102' in the CodeSystem 'http://snomed.info/sct' version 'http://snomed.info/sct/900000000000207008/version/20240201'",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -1707,7 +1689,6 @@ v: {
"error" : "Unknown code '717121000000105' in the CodeSystem 'http://snomed.info/sct' version 'http://snomed.info/sct/900000000000207008/version/20240201'",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -1749,7 +1730,6 @@ v: {
"error" : "Unknown code '933361000000108' in the CodeSystem 'http://snomed.info/sct' version 'http://snomed.info/sct/900000000000207008/version/20240201'",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -1791,7 +1771,6 @@ v: {
"error" : "Unknown code '887171000000109' in the CodeSystem 'http://snomed.info/sct' version 'http://snomed.info/sct/900000000000207008/version/20240201'",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -1833,7 +1812,6 @@ v: {
"error" : "Unknown code '887201000000105' in the CodeSystem 'http://snomed.info/sct' version 'http://snomed.info/sct/900000000000207008/version/20240201'",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -1875,7 +1853,6 @@ v: {
"error" : "Unknown code '1052951000000105' in the CodeSystem 'http://snomed.info/sct' version 'http://snomed.info/sct/900000000000207008/version/20240201'",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -1917,7 +1894,6 @@ v: {
"error" : "Unknown code '886731000000109' in the CodeSystem 'http://snomed.info/sct' version 'http://snomed.info/sct/900000000000207008/version/20240201'",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -1959,7 +1935,6 @@ v: {
"error" : "Unknown code '887231000000104' in the CodeSystem 'http://snomed.info/sct' version 'http://snomed.info/sct/900000000000207008/version/20240201'",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -2001,7 +1976,6 @@ v: {
"error" : "Unknown code '9290701000001101' in the CodeSystem 'http://snomed.info/sct' version 'http://snomed.info/sct/900000000000207008/version/20240201'",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -2042,7 +2016,6 @@ v: {
"system" : "http://snomed.info/sct",
"version" : "http://snomed.info/sct/900000000000207008/version/20240201",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -2066,7 +2039,6 @@ v: {
"system" : "http://snomed.info/sct",
"version" : "http://snomed.info/sct/900000000000207008/version/20240201",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -2089,7 +2061,6 @@ v: {
"system" : "http://snomed.info/sct",
"version" : "http://snomed.info/sct/900000000000207008/version/20240201",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -2113,7 +2084,6 @@ v: {
"error" : "Unknown code '11181000146103' in the CodeSystem 'http://snomed.info/sct' version 'http://snomed.info/sct/900000000000207008/version/20240201'",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -2137,3 +2107,61 @@ v: {
}
-------------------------------------------------------------------------------------
{"code" : {
"coding" : [{
"system" : "http://snomed.info/sct",
"code" : "17621005",
"display" : "Normal (qualifier value)"
}]
}, "url": "http://hl7.org/fhir/ValueSet/security-labels", "version": "3.0.2", "langs":"en-US", "useServer":"true", "useClient":"true", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"version" : "http://snomed.info/sct/900000000000207008/version/20240201",
"severity" : "error",
"error" : "No valid coding was found for the value set 'http://hl7.org/fhir/ValueSet/security-labels|3.0.2'; The provided code 'http://snomed.info/sct#17621005 ('Normal (qualifier value)')' was not found in the value set 'http://hl7.org/fhir/ValueSet/security-labels|3.0.2'",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r3",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-server",
"valueUrl" : "http://tx-dev.fhir.org/r3"
}],
"severity" : "information",
"code" : "code-invalid",
"details" : {
"coding" : [{
"system" : "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
"code" : "this-code-not-in-vs"
}],
"text" : "The provided code 'http://snomed.info/sct#17621005 ('Normal (qualifier value)')' was not found in the value set 'http://hl7.org/fhir/ValueSet/security-labels|3.0.2'"
},
"location" : ["CodeableConcept.coding[0].code"],
"expression" : ["CodeableConcept.coding[0].code"]
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-server",
"valueUrl" : "http://tx-dev.fhir.org/r3"
}],
"severity" : "error",
"code" : "code-invalid",
"details" : {
"coding" : [{
"system" : "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
"code" : "not-in-vs"
}],
"text" : "No valid coding was found for the value set 'http://hl7.org/fhir/ValueSet/security-labels|3.0.2'"
}
}]
}
}
-------------------------------------------------------------------------------------

View File

@ -39,10 +39,68 @@ v: {
"system" : "http://www.ada.org/snodent",
"version" : "2.1.0",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
}
-------------------------------------------------------------------------------------
{"code" : {
"coding" : [{
"system" : "http://www.ada.org/snodent",
"code" : "210965D",
"display" : "Anterior part of lower alveolar ridge"
}],
"text" : "Anterior part of lower alveolar ridge"
}, "url": "http://hl7.org/fhir/us/dental-data-exchange/ValueSet/dental-anatomy", "version": "1.0.0", "langs":"en-US", "useServer":"true", "useClient":"true", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"version" : "2.1.0",
"severity" : "error",
"error" : "No valid coding was found for the value set 'http://hl7.org/fhir/us/dental-data-exchange/ValueSet/dental-anatomy|1.0.0'; The provided code 'http://www.ada.org/snodent#210965D ('Anterior part of lower alveolar ridge')' was not found in the value set 'http://hl7.org/fhir/us/dental-data-exchange/ValueSet/dental-anatomy|1.0.0'",
"class" : "UNKNOWN",
"server" : "http://local.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-server",
"valueUrl" : "http://local.fhir.org/r4"
}],
"severity" : "information",
"code" : "code-invalid",
"details" : {
"coding" : [{
"system" : "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
"code" : "this-code-not-in-vs"
}],
"text" : "The provided code 'http://www.ada.org/snodent#210965D ('Anterior part of lower alveolar ridge')' was not found in the value set 'http://hl7.org/fhir/us/dental-data-exchange/ValueSet/dental-anatomy|1.0.0'"
},
"location" : ["CodeableConcept.coding[0].code"],
"expression" : ["CodeableConcept.coding[0].code"]
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-server",
"valueUrl" : "http://local.fhir.org/r4"
}],
"severity" : "error",
"code" : "code-invalid",
"details" : {
"coding" : [{
"system" : "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
"code" : "not-in-vs"
}],
"text" : "No valid coding was found for the value set 'http://hl7.org/fhir/us/dental-data-exchange/ValueSet/dental-anatomy|1.0.0'"
}
}]
}
}
-------------------------------------------------------------------------------------

View File

@ -8422,7 +8422,6 @@ v: {
"error" : "Wrong Display Name 'O2 % BldC Oximetry' for http://loinc.org#59408-5. Valid display is 'Oxygen saturation in Arterial blood by Pulse oximetry' (en-US) (for the language(s) 'en-US')",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -8463,7 +8462,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -8489,7 +8487,6 @@ v: {
"error" : "The provided code 'http://loinc.org#59408-5' was not found in the value set 'http://hl7.org/fhir/ValueSet/observation-vitalsignresult--0|4.0.1'",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -8529,7 +8526,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -8553,7 +8549,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -8579,7 +8574,6 @@ v: {
"error" : "The provided code 'http://loinc.org#3150-0' was not found in the value set 'http://hl7.org/fhir/ValueSet/observation-vitalsignresult--0|4.0.1'",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -8623,7 +8617,6 @@ v: {
"error" : "Wrong Display Name 'Flow Rate' for http://loinc.org#3151-8. Valid display is 'Inhaled oxygen flow rate' (en-US) (for the language(s) 'en-US')",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -8666,7 +8659,6 @@ v: {
"error" : "The provided code 'http://loinc.org#3151-8' was not found in the value set 'http://hl7.org/fhir/ValueSet/observation-vitalsignresult--0|4.0.1'",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -8706,7 +8698,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -8732,7 +8723,6 @@ v: {
"error" : "The provided code 'http://loinc.org#2708-6' was not found in the value set 'http://hl7.org/fhir/us/core/ValueSet/us-core-vital-signs--0|4.0.0'",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -8772,7 +8762,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -8795,7 +8784,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -8818,7 +8806,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -8844,7 +8831,6 @@ v: {
"error" : "The provided code 'http://loinc.org#100066-0' was not found in the value set 'http://hl7.org/fhir/test/StructureDefinition/additional-bindings-vs1--0|1.0.0'",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -8884,7 +8870,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -8907,7 +8892,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -8930,7 +8914,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -8954,7 +8937,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -8978,7 +8960,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9002,7 +8983,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9026,7 +9006,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9049,7 +9028,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9073,7 +9051,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9096,7 +9073,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9120,7 +9096,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9143,7 +9118,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9167,7 +9141,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9190,7 +9163,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9214,7 +9186,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9237,7 +9208,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9261,7 +9231,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9284,7 +9253,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9308,7 +9276,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9332,7 +9299,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9359,7 +9325,6 @@ v: {
"error" : "Wrong Display Name 'Patient Authorization Signature' for http://loinc.org#59284-0. Valid display is 'Consent Document' (en-US) (for the language(s) 'en-US')",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -9399,7 +9364,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9423,7 +9387,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9446,7 +9409,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9470,7 +9432,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9494,7 +9455,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9518,7 +9478,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9545,7 +9504,6 @@ v: {
"error" : "Wrong Display Name 'NDC labeler code request' for http://loinc.org#51726-8. Valid display is 'FDA product label NDC labeler code request' (en-US) (for the language(s) 'en-US')",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -9586,7 +9544,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9611,7 +9568,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9634,7 +9590,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9662,7 +9617,6 @@ v: {
"error" : "Wrong Display Name 'Allergies and adverse reactions' for http://loinc.org#48765-2. Valid display is 'Allergies and adverse reactions Document' (en-US) (for the language(s) 'en-US')",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -9703,7 +9657,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9726,7 +9679,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9749,7 +9701,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9773,7 +9724,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9796,7 +9746,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9821,7 +9770,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9845,7 +9793,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9868,7 +9815,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9892,7 +9838,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9915,7 +9860,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9939,7 +9883,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9962,7 +9905,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -9986,7 +9928,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10010,7 +9951,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10033,7 +9973,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10057,7 +9996,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10080,7 +10018,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10103,7 +10040,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10128,7 +10064,6 @@ v: {
"error" : "Unknown code '<27>g<EFBFBD><67>' in the CodeSystem 'http://loinc.org' version '2.77'",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -10169,7 +10104,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10196,7 +10130,6 @@ v: {
"error" : "Wrong Display Name '<27><><EFBFBD><EFBFBD>' for http://loinc.org#18684-1. Valid display is 'First Blood pressure Set' (en-US) (for the language(s) 'en-US')",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -10240,7 +10173,6 @@ v: {
"error" : "Wrong Display Name '<27><><EFBFBD>k<EFBFBD><6B><EFBFBD><EFBFBD><EFBFBD><EFBFBD>' for http://loinc.org#8480-6. Valid display is 'Systolic blood pressure' (en-US) (for the language(s) 'en-US')",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -10284,7 +10216,6 @@ v: {
"error" : "Wrong Display Name '<27>g<EFBFBD><67><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>' for http://loinc.org#8462-4. Valid display is 'Diastolic blood pressure' (en-US) (for the language(s) 'en-US')",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -10325,7 +10256,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10349,7 +10279,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10373,7 +10302,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10397,7 +10325,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10422,7 +10349,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10447,7 +10373,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10471,7 +10396,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10495,7 +10419,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10518,7 +10441,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10541,7 +10463,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10564,7 +10485,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10587,7 +10507,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10610,7 +10529,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10633,7 +10551,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10656,7 +10573,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10679,7 +10595,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10702,7 +10617,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10737,7 +10651,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10772,7 +10685,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10807,7 +10719,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10831,7 +10742,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10854,7 +10764,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10877,7 +10786,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10901,7 +10809,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10927,7 +10834,6 @@ v: {
"error" : "The provided code 'http://loinc.org#76534-7' was not found in the value set 'http://hl7.org/fhir/ValueSet/observation-vitalsignresult--0|4.0.1'",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
@ -10967,7 +10873,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -10991,7 +10896,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -11015,7 +10919,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -11039,7 +10942,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -11063,7 +10965,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -11087,7 +10988,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -11111,7 +11011,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -11135,7 +11034,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -11158,7 +11056,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -11181,7 +11078,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -11205,7 +11101,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -11229,7 +11124,6 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -11252,6 +11146,82 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"issues" : {
"resourceType" : "OperationOutcome"
}
}
-------------------------------------------------------------------------------------
{"code" : {
"coding" : [{
"system" : "http://loinc.org",
"code" : "59408-5",
"display" : "O2 % BldC Oximetry"
},
{
"system" : "http://loinc.org",
"code" : "2708-6",
"display" : "Oxygen saturation in Arterial blood"
}]
}, "url": "http://hl7.org/fhir/us/core/ValueSet/us-core-vital-signs", "version": "4.0.0", "langs":"en-US", "useServer":"true", "useClient":"true", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"display" : "Oxygen saturation in Arterial blood",
"code" : "2708-6",
"system" : "http://loinc.org",
"version" : "2.78",
"severity" : "error",
"error" : "Wrong Display Name 'O2 % BldC Oximetry' for http://loinc.org#59408-5. Valid display is one of 3 choices: 'Oxygen saturation in Arterial blood by Pulse oximetry' (en-US), 'Oxygen saturation in Arterial blood by Pulse oximetry' (en-US) or 'SaO2 % BldA PulseOx' (en-US) (for the language(s) 'en-US')",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-server",
"valueUrl" : "http://tx-dev.fhir.org/r4"
}],
"severity" : "error",
"code" : "invalid",
"details" : {
"coding" : [{
"system" : "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
"code" : "invalid-display"
}],
"text" : "Wrong Display Name 'O2 % BldC Oximetry' for http://loinc.org#59408-5. Valid display is one of 3 choices: 'Oxygen saturation in Arterial blood by Pulse oximetry' (en-US), 'Oxygen saturation in Arterial blood by Pulse oximetry' (en-US) or 'SaO2 % BldA PulseOx' (en-US) (for the language(s) 'en-US')"
},
"location" : ["CodeableConcept.coding[0].display"],
"expression" : ["CodeableConcept.coding[0].display"]
}]
}
}
-------------------------------------------------------------------------------------
{"code" : {
"coding" : [{
"system" : "http://loinc.org",
"code" : "3150-0",
"display" : "Inhaled Oxygen Concentration"
}]
}, "url": "http://hl7.org/fhir/us/core/ValueSet/us-core-vital-signs", "version": "4.0.0", "langs":"en-US", "useServer":"true", "useClient":"true", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"display" : "Inhaled oxygen concentration",
"code" : "3150-0",
"system" : "http://loinc.org",
"version" : "2.78",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
@ -11259,3 +11229,49 @@ v: {
}
-------------------------------------------------------------------------------------
{"code" : {
"coding" : [{
"system" : "http://loinc.org",
"code" : "3151-8",
"display" : "Flow Rate"
}]
}, "url": "http://hl7.org/fhir/us/core/ValueSet/us-core-vital-signs", "version": "4.0.0", "langs":"en-US", "useServer":"true", "useClient":"true", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"display" : "Inhaled oxygen flow rate",
"code" : "3151-8",
"system" : "http://loinc.org",
"version" : "2.78",
"severity" : "error",
"error" : "Wrong Display Name 'Flow Rate' for http://loinc.org#3151-8. Valid display is one of 4 choices: 'Inhaled oxygen flow rate' (en-US), 'Inhaled oxygen flow rate' (en-US), 'Inhaled O2 flow rate' (en-US) or 'Inhaled oxygen' (en-US) (for the language(s) 'en-US')",
"class" : "UNKNOWN",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-server",
"valueUrl" : "http://tx-dev.fhir.org/r4"
}],
"severity" : "error",
"code" : "invalid",
"details" : {
"coding" : [{
"system" : "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
"code" : "invalid-display"
}],
"text" : "Wrong Display Name 'Flow Rate' for http://loinc.org#3151-8. Valid display is one of 4 choices: 'Inhaled oxygen flow rate' (en-US), 'Inhaled oxygen flow rate' (en-US), 'Inhaled O2 flow rate' (en-US) or 'Inhaled oxygen' (en-US) (for the language(s) 'en-US')"
},
"location" : ["CodeableConcept.coding[0].display"],
"expression" : ["CodeableConcept.coding[0].display"]
}]
}
}
-------------------------------------------------------------------------------------

View File

@ -1,3 +1,4 @@
[servers]
tx-dev.fhir.org.r4 = http://tx-dev.fhir.org/r4
local.fhir.org.r4 = http://local.fhir.org/r4

View File

@ -0,0 +1,42 @@
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://hl7.org/fhir/test/StructureDefinition/additional-bindings-profile-cs",
"code" : "digital-access"
}, "valueSet" :null, "langs":"en-US", "useServer":"true", "useClient":"false", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"code" : "digital-access",
"system" : "http://hl7.org/fhir/test/StructureDefinition/additional-bindings-profile-cs",
"severity" : "error",
"error" : "A definition for CodeSystem 'http://hl7.org/fhir/test/StructureDefinition/additional-bindings-profile-cs' could not be found, so the code cannot be validated",
"class" : "CODESYSTEM_UNSUPPORTED",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "http://hl7.org/fhir/test/StructureDefinition/additional-bindings-profile-cs",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-server",
"valueUrl" : "http://tx-dev.fhir.org/r4"
}],
"severity" : "error",
"code" : "not-found",
"details" : {
"coding" : [{
"system" : "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
"code" : "not-found"
}],
"text" : "A definition for CodeSystem 'http://hl7.org/fhir/test/StructureDefinition/additional-bindings-profile-cs' could not be found, so the code cannot be validated"
},
"location" : ["Coding.system"],
"expression" : ["Coding.system"]
}]
}
}
-------------------------------------------------------------------------------------

View File

@ -0,0 +1,83 @@
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://hl7.org/fhir/us/sdoh-clinicalcare/CodeSystem/SDOHCC-CodeSystemTemporaryCodes",
"code" : "digital-access-x"
}, "valueSet" :null, "langs":"en-US", "useServer":"true", "useClient":"false", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"code" : "digital-access-x",
"system" : "http://hl7.org/fhir/us/sdoh-clinicalcare/CodeSystem/SDOHCC-CodeSystemTemporaryCodes",
"severity" : "error",
"error" : "A definition for CodeSystem 'http://hl7.org/fhir/us/sdoh-clinicalcare/CodeSystem/SDOHCC-CodeSystemTemporaryCodes' could not be found, so the code cannot be validated",
"class" : "CODESYSTEM_UNSUPPORTED",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "http://hl7.org/fhir/us/sdoh-clinicalcare/CodeSystem/SDOHCC-CodeSystemTemporaryCodes",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-server",
"valueUrl" : "http://tx-dev.fhir.org/r4"
}],
"severity" : "error",
"code" : "not-found",
"details" : {
"coding" : [{
"system" : "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
"code" : "not-found"
}],
"text" : "A definition for CodeSystem 'http://hl7.org/fhir/us/sdoh-clinicalcare/CodeSystem/SDOHCC-CodeSystemTemporaryCodes' could not be found, so the code cannot be validated"
},
"location" : ["Coding.system"],
"expression" : ["Coding.system"]
}]
}
}
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://hl7.org/fhir/us/sdoh-clinicalcare/CodeSystem/SDOHCC-CodeSystemTemporaryCodes",
"code" : "digital-access"
}, "valueSet" :null, "langs":"en-US", "useServer":"true", "useClient":"false", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"code" : "digital-access",
"system" : "http://hl7.org/fhir/us/sdoh-clinicalcare/CodeSystem/SDOHCC-CodeSystemTemporaryCodes",
"severity" : "error",
"error" : "A definition for CodeSystem 'http://hl7.org/fhir/us/sdoh-clinicalcare/CodeSystem/SDOHCC-CodeSystemTemporaryCodes' could not be found, so the code cannot be validated",
"class" : "CODESYSTEM_UNSUPPORTED",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "http://hl7.org/fhir/us/sdoh-clinicalcare/CodeSystem/SDOHCC-CodeSystemTemporaryCodes",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-server",
"valueUrl" : "http://tx-dev.fhir.org/r4"
}],
"severity" : "error",
"code" : "not-found",
"details" : {
"coding" : [{
"system" : "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
"code" : "not-found"
}],
"text" : "A definition for CodeSystem 'http://hl7.org/fhir/us/sdoh-clinicalcare/CodeSystem/SDOHCC-CodeSystemTemporaryCodes' could not be found, so the code cannot be validated"
},
"location" : ["Coding.system"],
"expression" : ["Coding.system"]
}]
}
}
-------------------------------------------------------------------------------------

View File

@ -82,3 +82,45 @@ v: {
}
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://hl7.org/fhir/uv/ips/CodeSystem/absent-unknown-uv-ips",
"code" : "no-allergy-info",
"display" : "No information about allergies"
}, "valueSet" :null, "langs":"en-NZ", "useServer":"true", "useClient":"false", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"code" : "no-allergy-info",
"system" : "http://hl7.org/fhir/uv/ips/CodeSystem/absent-unknown-uv-ips",
"severity" : "error",
"error" : "A definition for CodeSystem 'http://hl7.org/fhir/uv/ips/CodeSystem/absent-unknown-uv-ips' could not be found, so the code cannot be validated",
"class" : "CODESYSTEM_UNSUPPORTED",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "http://hl7.org/fhir/uv/ips/CodeSystem/absent-unknown-uv-ips",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-server",
"valueUrl" : "http://tx-dev.fhir.org/r4"
}],
"severity" : "error",
"code" : "not-found",
"details" : {
"coding" : [{
"system" : "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
"code" : "not-found"
}],
"text" : "A definition for CodeSystem 'http://hl7.org/fhir/uv/ips/CodeSystem/absent-unknown-uv-ips' could not be found, so the code cannot be validated"
},
"location" : ["Coding.system"],
"expression" : ["Coding.system"]
}]
}
}
-------------------------------------------------------------------------------------

View File

@ -1038,7 +1038,6 @@ v: {
"system" : "http://unitsofmeasure.org",
"version" : "2.0.1",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -1059,7 +1058,6 @@ v: {
"code" : "fr-CA",
"system" : "urn:ietf:bcp:47",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -1081,10 +1079,96 @@ v: {
"system" : "http://unitsofmeasure.org",
"version" : "2.0.1",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
}
-------------------------------------------------------------------------------------
{"code" : {
"coding" : [{
"system" : "http://unstats.un.org/unsd/methods/m49/m49.htm",
"code" : "001"
}]
}, "url": "http://hl7.org/fhir/ValueSet/jurisdiction", "version": "5.0.0", "langs":"en-US", "useServer":"true", "useClient":"true", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"display" : "World",
"code" : "001",
"system" : "http://unstats.un.org/unsd/methods/m49/m49.htm",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-message-id",
"valueString" : "MSG_DEPRECATED"
},
{
"url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-server",
"valueUrl" : "http://tx-dev.fhir.org/r4"
}],
"severity" : "information",
"code" : "business-rule",
"details" : {
"coding" : [{
"system" : "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
"code" : "status-check"
}],
"text" : "Reference to deprecated ValueSet http://hl7.org/fhir/ValueSet/jurisdiction|5.0.0"
}
}]
}
}
-------------------------------------------------------------------------------------
{"code" : {
"coding" : [{
"system" : "http://unstats.un.org/unsd/methods/m49/m49.htm",
"code" : "001",
"display" : "World"
}]
}, "url": "http://hl7.org/fhir/ValueSet/jurisdiction", "version": "5.0.0", "langs":"en-US", "useServer":"true", "useClient":"true", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"display" : "World",
"code" : "001",
"system" : "http://unstats.un.org/unsd/methods/m49/m49.htm",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome",
"issue" : [{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-message-id",
"valueString" : "MSG_DEPRECATED"
},
{
"url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-server",
"valueUrl" : "http://tx-dev.fhir.org/r4"
}],
"severity" : "information",
"code" : "business-rule",
"details" : {
"coding" : [{
"system" : "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
"code" : "status-check"
}],
"text" : "Reference to deprecated ValueSet http://hl7.org/fhir/ValueSet/jurisdiction|5.0.0"
}
}]
}
}
-------------------------------------------------------------------------------------

View File

@ -14,14 +14,14 @@
HAPI FHIR
-->
<artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.27-SNAPSHOT</version>
<version>6.3.30-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<commons_compress_version>1.26.0</commons_compress_version>
<guava_version>32.0.1-jre</guava_version>
<hapi_fhir_version>6.4.1</hapi_fhir_version>
<validator_test_case_version>1.5.23-SNAPSHOT</validator_test_case_version>
<validator_test_case_version>1.5.24</validator_test_case_version>
<jackson_version>2.17.0</jackson_version>
<junit_jupiter_version>5.9.2</junit_jupiter_version>
<junit_platform_launcher_version>1.8.2</junit_platform_launcher_version>