Merge branch 'master' into issue_438

This commit is contained in:
Grahame Grieve 2021-03-29 09:08:04 +10:00 committed by GitHub
commit 30be8a0dc1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
54 changed files with 893 additions and 283 deletions

View File

@ -1,4 +1,6 @@
* add test for Observation conversion from 10 to 40
* add procedures conversion form dstu2 to r4
* add medication conversion from dstu2 to r4
* add copy of extension field for Enumeration fieldtype by Resource.copy
* add copy of extension field for Enumeration fieldtype by Resource.copy
* minor fixes in code generators for R4B
* add default value to Medication Request during conversion from dstu2 to r4

View File

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

View File

@ -967,7 +967,7 @@ public class VersionConvertor_40_50 {
if (src == null) return null;
org.hl7.fhir.r5.model.DataRequirement tgt = new org.hl7.fhir.r5.model.DataRequirement();
copyElement(src, tgt);
if (src.hasType()) tgt.setType(org.hl7.fhir.r5.model.Enumerations.FHIRAllTypes.fromCode(src.getType()));
if (src.hasType()) tgt.setType(org.hl7.fhir.r5.model.Enumerations.FHIRAllTypes.fromCode(convertResourceName4to5(src.getType())));
for (org.hl7.fhir.r4.model.CanonicalType t : src.getProfile()) tgt.getProfile().add(convertCanonical(t));
if (src.hasSubject()) tgt.setSubject(convertType(src.getSubject()));
for (org.hl7.fhir.r4.model.StringType t : src.getMustSupport()) tgt.getMustSupport().add(convertString(t));
@ -981,11 +981,12 @@ public class VersionConvertor_40_50 {
return tgt;
}
public static org.hl7.fhir.r4.model.DataRequirement convertDataRequirement(org.hl7.fhir.r5.model.DataRequirement src) throws FHIRException {
if (src == null) return null;
org.hl7.fhir.r4.model.DataRequirement tgt = new org.hl7.fhir.r4.model.DataRequirement();
copyElement(src, tgt);
if (src.hasType()) tgt.setType(src.getType().toCode());
if (src.hasType()) tgt.setType(convertResourceName5to4(src.getType().toCode()));
for (org.hl7.fhir.r5.model.CanonicalType t : src.getProfile()) tgt.getProfile().add(convertCanonical(t));
if (src.hasSubject()) tgt.setSubject(convertType(src.getSubject()));
for (org.hl7.fhir.r5.model.StringType t : src.getMustSupport()) tgt.getMustSupport().add(convertString(t));
@ -999,6 +1000,22 @@ public class VersionConvertor_40_50 {
return tgt;
}
private static String convertResourceName4to5(String name) {
if (name == null) return null;
if (name.equals("MedicationStatement")) {
return "MedicationUsage";
}
return name;
}
private static String convertResourceName5to4(String name) {
if (name == null) return null;
if (name.equals("MedicationUsage")) {
return "MedicationStatement";
}
return name;
}
public static org.hl7.fhir.r5.model.DataRequirement.DataRequirementCodeFilterComponent convertDataRequirementCodeFilterComponent(org.hl7.fhir.r4.model.DataRequirement.DataRequirementCodeFilterComponent src) throws FHIRException {
if (src == null) return null;
org.hl7.fhir.r5.model.DataRequirement.DataRequirementCodeFilterComponent tgt = new org.hl7.fhir.r5.model.DataRequirement.DataRequirementCodeFilterComponent();

View File

@ -18,6 +18,8 @@ public class MedicationRequest10_40 {
tgt.setAuthoredOnElement(VersionConvertor_10_40.convertDateTime(src.getDateWrittenElement()));
if (src.hasStatus())
tgt.setStatus(org.hl7.fhir.r4.model.MedicationRequest.MedicationRequestStatus.fromCode(src.getStatus().toCode()));
else
tgt.setStatus(org.hl7.fhir.r4.model.MedicationRequest.MedicationRequestStatus.UNKNOWN);
if (src.hasPatient())
tgt.setSubject(VersionConvertor_10_40.convertReference(src.getPatient()));
if (src.hasPrescriber())

View File

@ -167,11 +167,14 @@ public class ConceptMap40_50 extends VersionConvertor_40_50 {
if (src.hasCode())
tgt.setCodeElement(convertCode(src.getCodeElement()));
if (src.hasDisplay())
tgt.setDisplayElement(convertString(src.getDisplayElement()));
for (org.hl7.fhir.r4.model.ConceptMap.TargetElementComponent t : src.getTarget()) if (t.getEquivalence() == org.hl7.fhir.r4.model.Enumerations.ConceptMapEquivalence.UNMATCHED) {
tgt.setDisplayElement(convertString(src.getDisplayElement()));
for (org.hl7.fhir.r4.model.ConceptMap.TargetElementComponent t : src.getTarget()) {
if (t.getEquivalence() == org.hl7.fhir.r4.model.Enumerations.ConceptMapEquivalence.UNMATCHED) {
tgt.setNoMap(true);
} else {
}
else {
tgt.addTarget(convertTargetElementComponent(t));
}
}
return tgt;
}
@ -222,6 +225,8 @@ public class ConceptMap40_50 extends VersionConvertor_40_50 {
tgt.setDisplayElement(convertString(src.getDisplayElement()));
if (src.hasRelationship())
tgt.setEquivalenceElement(convertConceptMapEquivalence(src.getRelationshipElement()));
else
tgt.setEquivalence(ConceptMapEquivalence.RELATEDTO);
if (src.hasComment())
tgt.setCommentElement(convertString(src.getCommentElement()));
for (org.hl7.fhir.r5.model.ConceptMap.OtherElementComponent t : src.getDependsOn()) tgt.addDependsOn(convertOtherElementComponent(t));

View File

@ -210,6 +210,9 @@ public class Enumerations40_50 extends VersionConvertor_40_50 {
case _4_0_1:
tgt.setValue(org.hl7.fhir.r5.model.Enumerations.FHIRVersion._4_0_1);
break;
case _4_1_0:
tgt.setValue(org.hl7.fhir.r5.model.Enumerations.FHIRVersion._4_1_0);
break;
default:
tgt.setValue(org.hl7.fhir.r5.model.Enumerations.FHIRVersion.NULL);
break;
@ -292,6 +295,9 @@ public class Enumerations40_50 extends VersionConvertor_40_50 {
case _4_0_1:
tgt.setValue(org.hl7.fhir.r4.model.Enumerations.FHIRVersion._4_0_1);
break;
case _4_1_0:
tgt.setValue(org.hl7.fhir.r4.model.Enumerations.FHIRVersion._4_1_0);
break;
default:
tgt.setValue(org.hl7.fhir.r4.model.Enumerations.FHIRVersion.NULL);
break;

View File

@ -0,0 +1,50 @@
package org.hl7.fhir.convertors.misc;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.json.JsonTrackingParser;
import org.hl7.fhir.utilities.npm.NpmPackage;
import com.google.gson.JsonObject;
public class CorePackageTools {
public static void main(String[] args) throws FHIRFormatError, FileNotFoundException, IOException {
if ("-xml".equals(args[0])) {
new CorePackageTools().buildXml(args[1], args[2], args[3]);
}
if ("-pack".equals(args[0])) {
new CorePackageTools().buildPackage(args[1], args[2]);
}
}
private void buildPackage(String path, String output) throws IOException {
NpmPackage npm = NpmPackage.fromFolder(path);
npm.loadAllFiles();
npm.save(new FileOutputStream(output));
}
private void buildXml(String json, String xml, String version) throws FHIRFormatError, FileNotFoundException, IOException {
for (File f : new File(Utilities.path(json, "package")).listFiles()) {
if (f.getName().endsWith(".json")) {
JsonObject j = new JsonTrackingParser().parseJson(f);
if (j.has("resourceType")) {
if ("1.4".equals(version)) {
String n = f.getName();
System.out.println(n);
String xn = Utilities.changeFileExt(n, ".xml");
org.hl7.fhir.dstu2016may.model.Resource r = new org.hl7.fhir.dstu2016may.formats.JsonParser().parse(new FileInputStream(f));
new org.hl7.fhir.dstu2016may.formats.XmlParser().setOutputStyle(org.hl7.fhir.dstu2016may.formats.IParser.OutputStyle.NORMAL).compose(new FileOutputStream(Utilities.path(xml, "package", xn)), r);
}
}
}
}
}
}

View File

@ -6,16 +6,28 @@ import org.hl7.fhir.convertors.misc.IGR2ConvertorAdvisor;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.io.IOException;
import java.io.InputStream;
import java.util.stream.Stream;
public class MedicationRequest10_40Test {
@Test
private static Stream<Arguments> filesPaths() {
return Stream.of(
Arguments.of("/0_medication_request_10.json", "/0_medication_request_40.json"),
Arguments.of("/1_medication_request_10.json", "/1_medication_request_40.json")
);
}
@ParameterizedTest
@MethodSource("filesPaths")
@DisplayName("Test 10_40 MedicationRequest conversion")
public void testMedicationRequestConversion() throws IOException {
InputStream dstu2_input = this.getClass().getResourceAsStream("/0_medication_request_10.json");
InputStream r4_exepected_input = this.getClass().getResourceAsStream("/0_medication_request_40.json");
public void testMedicationRequestConversion(String dstu2_path, String r4_path) throws IOException {
InputStream dstu2_input = this.getClass().getResourceAsStream(dstu2_path);
InputStream r4_exepected_input = this.getClass().getResourceAsStream(r4_path);
org.hl7.fhir.dstu2.model.MedicationOrder dstu2 = (org.hl7.fhir.dstu2.model.MedicationOrder) new org.hl7.fhir.dstu2.formats.JsonParser().parse(dstu2_input);
VersionConvertorAdvisor40 advisor = new IGR2ConvertorAdvisor();

View File

@ -0,0 +1,36 @@
{"resourceType": "MedicationOrder",
"dateWritten": "2016-11-13",
"id": "T5YI1tCzs--JEvCICFbx8zgB",
"identifier": [{"use": "usual",
"system": "urn:oid:1.2.840.114350.1.13.0.1.7.2.798268",
"value": "988736"},
{"use": "usual",
"system": "urn:oid:1.2.840.114350.1.13.0.1.7.3.798268.801",
"value": "988736:2150291843"}],
"patient": {"display": "Jason Argonaut",
"reference": "https://open-ic.epic.com/Argonaut/api/FHIR/DSTU2/Patient/Tbt3KuCY0B5PSrJvCu2j-PlK.aiHsu2xUjUM8bWpetXoB"},
"prescriber": {"display": "Historical Provider, MD",
"reference": "https://open-ic.epic.com/Argonaut/api/FHIR/DSTU2/Practitioner/T-kmjPGEVPAmnBfmx56HsKgB"},
"medicationReference": {"display": "amitriptyline 10 MG tablet",
"reference": "https://open-ic.epic.com/Argonaut/api/FHIR/DSTU2/Medication/T0eKLT7EB2ApMM8HCEURdMAB"},
"dosageInstruction": [{"text": "Take 10 mg by mouth nightly.",
"asNeededBoolean": "False",
"route": {"text": "Oral",
"coding": [{"system": "urn:oid:1.2.840.114350.1.13.0.1.7.4.698288.330",
"code": "15",
"display": "Oral"}]},
"method": {"text": "Take",
"coding": [{"system": "urn:oid:1.2.840.114350.1.13.0.1.7.4.798268.8600",
"code": "11",
"display": "Take"}]},
"timing": {"repeat": {"frequency": 1,
"period": 1.0,
"periodUnits": "d",
"boundsPeriod": {"start": "2016-11-15T00:00:00Z",
"end": "2016-11-23T00:00:00Z"}}},
"doseQuantity": {"value": 10.0,
"unit": "mg",
"code": "mg",
"system": "http://unitsofmeasure.org"}}],
"dispenseRequest": {"validityPeriod": {"start": "2016-11-15T00:00:00Z",
"end": "2016-11-23T00:00:00Z"}}}

View File

@ -0,0 +1,38 @@
{"resourceType": "MedicationRequest",
"id": "T5YI1tCzs--JEvCICFbx8zgB",
"identifier": [{"use": "usual",
"system": "urn:oid:1.2.840.114350.1.13.0.1.7.2.798268",
"value": "988736"},
{"use": "usual",
"system": "urn:oid:1.2.840.114350.1.13.0.1.7.3.798268.801",
"value": "988736:2150291843"}],
"status": "unknown",
"intent": "order",
"medicationReference": {"reference": "https://open-ic.epic.com/Argonaut/api/FHIR/DSTU2/Medication/T0eKLT7EB2ApMM8HCEURdMAB",
"display": "amitriptyline 10 MG tablet"},
"subject": {"reference": "https://open-ic.epic.com/Argonaut/api/FHIR/DSTU2/Patient/Tbt3KuCY0B5PSrJvCu2j-PlK.aiHsu2xUjUM8bWpetXoB",
"display": "Jason Argonaut"},
"authoredOn": "2016-11-13T00:00:00",
"requester": {"reference": "https://open-ic.epic.com/Argonaut/api/FHIR/DSTU2/Practitioner/T-kmjPGEVPAmnBfmx56HsKgB",
"display": "Historical Provider, MD"},
"dosageInstruction": [{"text": "Take 10 mg by mouth nightly.",
"timing": {"repeat": {"boundsPeriod": {"start": "2016-11-15T00:00:00Z",
"end": "2016-11-23T00:00:00Z"},
"frequency": 1,
"period": 1.0,
"periodUnit": "d"}},
"asNeededBoolean": "False",
"route": {"coding": [{"system": "urn:oid:1.2.840.114350.1.13.0.1.7.4.698288.330",
"code": "15",
"display": "Oral"}],
"text": "Oral"},
"method": {"coding": [{"system": "urn:oid:1.2.840.114350.1.13.0.1.7.4.798268.8600",
"code": "11",
"display": "Take"}],
"text": "Take"},
"doseAndRate": [{"doseQuantity": {"value": 10.0,
"unit": "mg",
"system": "http://unitsofmeasure.org",
"code": "mg"}}]}],
"dispenseRequest": {"validityPeriod": {"start": "2016-11-15T00:00:00Z",
"end": "2016-11-23T00:00:00Z"}}}

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>5.2.21-SNAPSHOT</version>
<version>5.3.7-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>5.2.21-SNAPSHOT</version>
<version>5.3.7-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>5.2.21-SNAPSHOT</version>
<version>5.3.7-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>5.2.21-SNAPSHOT</version>
<version>5.3.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -10032,6 +10032,10 @@ The primary difference between a medication statement and a medication administr
* added to help the parsers
*/
_4_0_1,
/**
* R4B - manually added
*/
_4_1_0,
NULL;
public static FHIRVersion fromCode(String codeString) throws FHIRException {
if (codeString == null || "".equals(codeString))
@ -10082,6 +10086,8 @@ The primary difference between a medication statement and a medication administr
return _4_0_0;
if ("4.0.1".equals(codeString))
return _4_0_1;
if ("4.1.0".equals(codeString))
return _4_1_0;
throw new FHIRException("Unknown FHIRVersion code '"+codeString+"'");
}
@Override
@ -10113,6 +10119,7 @@ The primary difference between a medication statement and a medication administr
case _3_5_0: return "3.5.0";
case _4_0_0: return "4.0.0";
case _4_0_1: return "4.0.1";
case _4_1_0: return "4.1.0";
case NULL: return null;
default: return "?";
}
@ -10142,6 +10149,7 @@ The primary difference between a medication statement and a medication administr
case _3_5_0: return "http://hl7.org/fhir/FHIR-version";
case _4_0_0: return "http://hl7.org/fhir/FHIR-version";
case _4_0_1: return "http://hl7.org/fhir/FHIR-version";
case _4_1_0: return "http://hl7.org/fhir/FHIR-version";
case NULL: return null;
default: return "?";
}
@ -10171,6 +10179,7 @@ The primary difference between a medication statement and a medication administr
case _3_5_0: return "R4 Ballot #2.";
case _4_0_0: return "FHIR Release 4 (Normative + STU).";
case _4_0_1: return "FHIR Release 4 Technical Correction #1.";
case _4_1_0: return "FHIR Release 4B";
case NULL: return null;
default: return "?";
}
@ -10200,6 +10209,7 @@ The primary difference between a medication statement and a medication administr
case _3_5_0: return "3.5.0";
case _4_0_0: return "4.0.0";
case _4_0_1: return "4.0.1";
case _4_1_0: return "4.1.0";
case NULL: return null;
default: return "?";
}
@ -10263,6 +10273,8 @@ The primary difference between a medication statement and a medication administr
return FHIRVersion._4_0_0;
if ("4.0.1".equals(codeString))
return FHIRVersion._4_0_1;
if ("4.1.0".equals(codeString))
return FHIRVersion._4_1_0;
throw new IllegalArgumentException("Unknown FHIRVersion code '"+codeString+"'");
}
public Enumeration<FHIRVersion> fromType(Base code) throws FHIRException {
@ -10319,6 +10331,8 @@ The primary difference between a medication statement and a medication administr
return new Enumeration<FHIRVersion>(this, FHIRVersion._4_0_0);
if ("4.0.1".equals(codeString))
return new Enumeration<FHIRVersion>(this, FHIRVersion._4_0_1);
if ("4.1.0".equals(codeString))
return new Enumeration<FHIRVersion>(this, FHIRVersion._4_1_0);
throw new FHIRException("Unknown FHIRVersion code '"+codeString+"'");
}
public String toCode(FHIRVersion code) {
@ -10368,6 +10382,8 @@ The primary difference between a medication statement and a medication administr
return "4.0.0";
if (code == FHIRVersion._4_0_1)
return "4.0.1";
if (code == FHIRVersion._4_1_0)
return "4.1.0";
return "?";
}
public String toSystem(FHIRVersion code) {

View File

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

View File

@ -636,6 +636,9 @@ public class ProfileUtilities extends TranslatingUtilities {
}
baseSnapshot = cloneSnapshot(baseSnapshot, base.getType(), derivedType);
}
// if (derived.getId().equals("2.16.840.1.113883.10.20.22.2.1.1")) {
// debug = true;
// }
processPaths("", derived.getSnapshot(), baseSnapshot, diff, baseCursor, diffCursor, baseSnapshot.getElement().size()-1,
derived.getDifferential().hasElement() ? derived.getDifferential().getElement().size()-1 : -1, url, webUrl, derived.present(), null, null, false, base.getUrl(), null, false, null, null, new ArrayList<ElementRedirection>(), base);
checkGroupConstraints(derived);
@ -1053,7 +1056,7 @@ public class ProfileUtilities extends TranslatingUtilities {
baseCursor = indexOfFirstNonChild(base, currentBase, baseCursor+1, baseLimit);
} else {
if (outcome.getType().size() == 0) {
throw new DefinitionException(context.formatMessage(I18nConstants._HAS_NO_CHILDREN__AND_NO_TYPES_IN_PROFILE_, diffMatches.get(0).getPath(), differential.getElement().get(diffCursor).getPath(), profileName));
throw new DefinitionException(context.formatMessage(I18nConstants._HAS_NO_CHILDREN__AND_NO_TYPES_IN_PROFILE_, cpath, differential.getElement().get(diffCursor).getPath(), profileName));
}
boolean nonExtension = false;
if (outcome.getType().size() > 1) {
@ -1072,7 +1075,7 @@ public class ProfileUtilities extends TranslatingUtilities {
}
StructureDefinition dt = outcome.getType().size() > 1 ? context.fetchTypeDefinition("Element") : getProfileForDataType(outcome.getType().get(0));
if (dt == null) {
throw new DefinitionException(context.formatMessage(I18nConstants.UNKNOWN_TYPE__AT_, outcome.getType().get(0), diffMatches.get(0).getPath()));
throw new DefinitionException(context.formatMessage(I18nConstants.UNKNOWN_TYPE__AT_, outcome.getType().get(0), cpath));
}
contextName = dt.getUrl();
int start = diffCursor;
@ -1388,7 +1391,7 @@ public class ProfileUtilities extends TranslatingUtilities {
// (but you might do that in order to split up constraints by type)
throw new DefinitionException(context.formatMessage(I18nConstants.ATTEMPT_TO_A_SLICE_AN_ELEMENT_THAT_DOES_NOT_REPEAT__FROM__IN_, currentBase.getPath(), currentBase.getPath(), contextName, url, diffMatches.get(0).getId(), sliceNames(diffMatches)));
if (!diffMatches.get(0).hasSlicing() && !isExtension(currentBase)) // well, the diff has set up a slice, but hasn't defined it. this is an error
throw new DefinitionException(context.formatMessage(I18nConstants.DIFFERENTIAL_DOES_NOT_HAVE_A_SLICE__B_OF_____IN_PROFILE_, currentBase.getPath(), baseCursor, baseLimit, diffCursor, diffLimit, url));
throw new DefinitionException(context.formatMessage(I18nConstants.DIFFERENTIAL_DOES_NOT_HAVE_A_SLICE__B_OF_____IN_PROFILE_, currentBase.getPath(), baseCursor, baseLimit, diffCursor, diffLimit, url, cpath));
// well, if it passed those preconditions then we slice the dest.
int start = 0;
@ -1792,7 +1795,7 @@ public class ProfileUtilities extends TranslatingUtilities {
removeStatusExtensions(outcome);
// --- LM Added this
diffCursor = differential.getElement().indexOf(diffItem)+1;
if (!outcome.getType().isEmpty() && (/*outcome.getType().get(0).getCode().equals("Extension") || */differential.getElement().size() > diffCursor) && outcome.getPath().contains(".") && isDataType(outcome.getType())) { // don't want to do this for the root, since that's base, and we're already processing it
if (!outcome.getType().isEmpty() && (/*outcome.getType().get(0).getCode().equals("Extension") || */differential.getElement().size() > diffCursor) && outcome.getPath().contains(".")/* && isDataType(outcome.getType())*/) { // don't want to do this for the root, since that's base, and we're already processing it
if (!baseWalksInto(base.getElement(), baseCursor)) {
if (differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), diffMatches.get(0).getPath()+".")) {
if (outcome.getType().size() > 1)
@ -4625,7 +4628,7 @@ public class ProfileUtilities extends TranslatingUtilities {
erow.getSubRows().add(row);
Cell c = gen.new Cell();
row.getCells().add(c);
c.addPiece(gen.new Piece((ed.getBase().getPath().equals(ed.getPath()) ? ref+ed.getPath() : corePath+(VersionUtilities.isThisOrLater("4.1", context.getVersion()) ? "types-definitions.html#"+ed.getBase().getPath() : "element-definitions.html#"+ed.getBase().getPath())), t.getName(), null));
c.addPiece(gen.new Piece((ed.getBase().getPath().equals(ed.getPath()) ? ref+ed.getPath() : corePath+(VersionUtilities.isR5Ver(context.getVersion()) ? "types-definitions.html#"+ed.getBase().getPath() : "element-definitions.html#"+ed.getBase().getPath())), t.getName(), null));
c = gen.new Cell();
row.getCells().add(c);
c.addPiece(gen.new Piece(null, null, null));

View File

@ -978,7 +978,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
}
if (vs != null) {
if (isTxCaching && cacheId != null && cached.contains(vs.getUrl()+"|"+vs.getVersion())) {
pin.addParameter().setName("url").setValue(new UriType(vs.getUrl()+"|"+vs.getVersion()));
pin.addParameter().setName("url").setValue(new UriType(vs.getUrl()+(vs.hasVersion() ? "|"+vs.getVersion() : "")));
} else {
pin.addParameter().setName("valueSet").setResource(vs);
cached.add(vs.getUrl()+"|"+vs.getVersion());

View File

@ -6568,7 +6568,7 @@ The primary difference between a medicationusage and a medicationadministration
*/
NULL;
public static final FHIRVersion R4B = FHIRVersion._4_0_1;
public static final FHIRVersion R4B = FHIRVersion._4_1_0;
public static FHIRVersion fromCode(String codeString) throws FHIRException {
if (codeString == null || "".equals(codeString))
@ -6824,6 +6824,10 @@ public String toCode(int len) {
public String toString() {
return toCode();
}
public boolean isR4B() {
return toCode().startsWith("4.1");
}
// end addition
}

View File

@ -67,10 +67,12 @@ public class GraphQLSchemaGenerator {
private static final String INNER_TYPE_NAME = "gql.type.name";
IWorkerContext context;
private ProfileUtilities profileUtilities;
private String version;
public GraphQLSchemaGenerator(IWorkerContext context) {
public GraphQLSchemaGenerator(IWorkerContext context, String version) {
super();
this.context = context;
this.version = version;
profileUtilities = new ProfileUtilities(context, null, null);
}
@ -87,7 +89,7 @@ public class GraphQLSchemaGenerator {
tl.put(sd.getName(), sd);
}
}
writer.write("# FHIR GraphQL Schema. Version "+Constants.VERSION+"\r\n\r\n");
writer.write("# FHIR GraphQL Schema. Version "+version+"\r\n\r\n");
writer.write("# FHIR Defined Primitive types\r\n");
for (String n : sorted(pl.keySet()))
generatePrimitive(writer, pl.get(n));
@ -107,7 +109,7 @@ public class GraphQLSchemaGenerator {
public void generateResource(OutputStream stream, StructureDefinition sd, List<SearchParameter> parameters, EnumSet<FHIROperationType> operations) throws IOException, FHIRException {
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stream));
writer.write("# FHIR GraphQL Schema. Version "+Constants.VERSION+"\r\n\r\n");
writer.write("# FHIR GraphQL Schema. Version "+version+"\r\n\r\n");
writer.write("# import the types from 'types.graphql'\r\n\r\n");
generateType(writer, sd);
if (operations.contains(FHIROperationType.READ))

View File

@ -276,6 +276,8 @@ public class NPMPackageGenerator {
return "hl7.fhir.r3.core";
if (v.startsWith("4.0"))
return "hl7.fhir.r4.core";
if (v.startsWith("4.1"))
return "hl7.fhir.r4b.core";
return null;
}

View File

@ -183,6 +183,7 @@ public class ToolingExtensions {
public static final String EXT_MUST_SUPPORT = "http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support";
public static final String EXT_TRANSLATABLE = "http://hl7.org/fhir/StructureDefinition/elementdefinition-translatable";
public static final String EXT_PATTERN = "http://hl7.org/fhir/StructureDefinition/elementdefinition-pattern";
public static final String EXT_BINDING_METHOD = "http://hl7.org/fhir/StructureDefinition/elementdefinition-binding-method";
// specific extension helpers

View File

@ -111,7 +111,7 @@ public class TypesUtilities {
res.add(new WildcardInformation("id", TypeClassification.PRIMITIVE));
res.add(new WildcardInformation("instant", TypeClassification.PRIMITIVE));
res.add(new WildcardInformation("integer", TypeClassification.PRIMITIVE));
if (!version.startsWith("4.0")) {
if (!version.startsWith("4.1")) {
res.add(new WildcardInformation("integer64", TypeClassification.PRIMITIVE));
}
res.add(new WildcardInformation("markdown", TypeClassification.PRIMITIVE));

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>5.2.21-SNAPSHOT</version>
<version>5.3.7-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>5.2.21-SNAPSHOT</version>
<version>5.3.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -465,4 +465,5 @@ public class VersionUtilities {
return null;
}
}

View File

@ -361,6 +361,8 @@ public class I18nConstants {
public static final String SD_ED_BIND_UNKNOWN_VS = "SD_ED_BIND_UNKNOWN_VS";
public static final String SD_ED_BIND_NOT_VS = "SD_ED_BIND_NOT_VS";
public static final String SD_ED_BIND_NO_BINDABLE = "SD_ED_BIND_NO_BINDABLE";
public static final String SD_VALUE_TYPE_IILEGAL = "SD_VALUE_TYPE_IILEGAL";
public static final String SD_NO_TYPES_OR_CONTENTREF = "SD_NO_TYPES_OR_CONTENTREF";
public static final String SEARCHPARAMETER_BASE_WRONG = "SEARCHPARAMETER_BASE_WRONG";
public static final String SEARCHPARAMETER_EXP_WRONG = "SEARCHPARAMETER_EXP_WRONG";
public static final String SEARCHPARAMETER_NOTFOUND = "SEARCHPARAMETER_NOTFOUND";
@ -386,9 +388,9 @@ public class I18nConstants {
public static final String TERMINOLOGY_TX_CODE_VALUESETMAX = "Terminology_TX_Code_ValueSetMax";
public static final String TERMINOLOGY_TX_CODE_VALUESET_EXT = "Terminology_TX_Code_ValueSet_Ext";
public static final String TERMINOLOGY_TX_CODING_COUNT = "Terminology_TX_Coding_Count";
public static final String TERMINOLOGY_TX_CONFIRM_1 = "Terminology_TX_Confirm_1";
public static final String TERMINOLOGY_TX_CONFIRM_2 = "Terminology_TX_Confirm_2";
public static final String TERMINOLOGY_TX_CONFIRM_3 = "Terminology_TX_Confirm_3";
public static final String TERMINOLOGY_TX_CONFIRM_1_CC = "Terminology_TX_Confirm_1_CC";
public static final String TERMINOLOGY_TX_CONFIRM_2_CC = "Terminology_TX_Confirm_2_CC";
public static final String TERMINOLOGY_TX_CONFIRM_3_CC = "Terminology_TX_Confirm_3_CC";
public static final String TERMINOLOGY_TX_CONFIRM_4a = "Terminology_TX_Confirm_4a";
public static final String TERMINOLOGY_TX_CONFIRM_4b = "Terminology_TX_Confirm_4b";
public static final String TERMINOLOGY_TX_CONFIRM_5 = "Terminology_TX_Confirm_5";
@ -398,7 +400,7 @@ public class I18nConstants {
public static final String TERMINOLOGY_TX_ERROR_CODEABLECONCEPT_MAX = "Terminology_TX_Error_CodeableConcept_Max";
public static final String TERMINOLOGY_TX_ERROR_CODING1 = "Terminology_TX_Error_Coding1";
public static final String TERMINOLOGY_TX_ERROR_CODING2 = "Terminology_TX_Error_Coding2";
public static final String TERMINOLOGY_TX_NOVALID_1 = "Terminology_TX_NoValid_1";
public static final String TERMINOLOGY_TX_NOVALID_1_CC = "Terminology_TX_NoValid_1_CC";
public static final String TERMINOLOGY_TX_NOVALID_10 = "Terminology_TX_NoValid_10";
public static final String TERMINOLOGY_TX_NOVALID_11 = "Terminology_TX_NoValid_11";
public static final String TERMINOLOGY_TX_NOVALID_12 = "Terminology_TX_NoValid_12";
@ -408,8 +410,8 @@ public class I18nConstants {
public static final String TERMINOLOGY_TX_NOVALID_16 = "Terminology_TX_NoValid_16";
public static final String TERMINOLOGY_TX_NOVALID_17 = "Terminology_TX_NoValid_17";
public static final String TERMINOLOGY_TX_NOVALID_18 = "Terminology_TX_NoValid_18";
public static final String TERMINOLOGY_TX_NOVALID_2 = "Terminology_TX_NoValid_2";
public static final String TERMINOLOGY_TX_NOVALID_3 = "Terminology_TX_NoValid_3";
public static final String TERMINOLOGY_TX_NOVALID_2_CC = "Terminology_TX_NoValid_2_CC";
public static final String TERMINOLOGY_TX_NOVALID_3_CC = "Terminology_TX_NoValid_3_CC";
public static final String TERMINOLOGY_TX_NOVALID_4 = "Terminology_TX_NoValid_4";
public static final String TERMINOLOGY_TX_NOVALID_5 = "Terminology_TX_NoValid_5";
public static final String TERMINOLOGY_TX_NOVALID_6 = "Terminology_TX_NoValid_6";

View File

@ -64,26 +64,37 @@ public abstract class BasePackageCacheManager implements IPackageCacheManager {
protected InputStreamWithSrc loadFromPackageServer(String id, String version) {
for (String nextPackageServer : getPackageServers()) {
PackageClient packageClient = myClientFactory.apply(nextPackageServer);
try {
if (Utilities.noString(version)) {
version = packageClient.getLatestVersion(id);
if (okToUsePackageServer(nextPackageServer, id)) {
PackageClient packageClient = myClientFactory.apply(nextPackageServer);
try {
if (Utilities.noString(version)) {
version = packageClient.getLatestVersion(id);
}
if (version.endsWith(".x")) {
version = packageClient.getLatestVersion(id, version);
}
InputStream stream = packageClient.fetch(id, version);
String url = packageClient.url(id, version);
return new InputStreamWithSrc(stream, url, version);
} catch (IOException e) {
ourLog.info("Failed to resolve package {}#{} from server: {}", id, version, nextPackageServer);
}
if (version.endsWith(".x")) {
version = packageClient.getLatestVersion(id, version);
}
InputStream stream = packageClient.fetch(id, version);
String url = packageClient.url(id, version);
return new InputStreamWithSrc(stream, url, version);
} catch (IOException e) {
ourLog.info("Failed to resolve package {}#{} from server: {}", id, version, nextPackageServer);
}
}
return null;
}
// hack - we have a hacked 1.4.0 out there. Only packages2.fhir.org has it.
// this is not a long term thing, but it's not clear how to release patches for
// 1.4.0
private boolean okToUsePackageServer(String server, String id) {
if ("http://packages.fhir.org".equals(server) && "hl7.fhir.r2b.core".equals(id)) {
return false;
}
return true;
}
public abstract NpmPackage loadPackageFromCacheOnly(String id, @Nullable String version) throws IOException;
@Override
@ -107,7 +118,7 @@ public abstract class BasePackageCacheManager implements IPackageCacheManager {
private String getPackageUrl(String packageId, String server) throws IOException {
PackageClient pc = myClientFactory.apply(server);
List<PackageClient.PackageInfo> res = pc.search(packageId, null, null, false);
List<PackageInfo> res = pc.search(packageId, null, null, false);
if (res.size() == 0) {
return null;
} else {
@ -135,12 +146,12 @@ public abstract class BasePackageCacheManager implements IPackageCacheManager {
return null;
}
PackageClient pc = myClientFactory.apply(server);
List<PackageClient.PackageInfo> res = pc.search(null, canonical, null, false);
List<PackageInfo> res = pc.search(null, canonical, null, false);
if (res.size() == 0) {
return null;
} else {
// this is driven by HL7 Australia (http://hl7.org.au/fhir/ is the canonical url for the base package, and the root for all the others)
for (PackageClient.PackageInfo pi : res) {
for (PackageInfo pi : res) {
if (canonical.equals(pi.getCanonical())) {
return pi.getId();
}

View File

@ -53,12 +53,10 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.security.cert.X509Certificate;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
@ -207,8 +205,8 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
private void listSpecs(Map<String, String> specList, String server) throws IOException {
CachingPackageClient pc = new CachingPackageClient(server);
List<PackageClient.PackageInfo> matches = pc.search(null, null, null, false);
for (PackageClient.PackageInfo m : matches) {
List<PackageInfo> matches = pc.search(null, null, null, false);
for (PackageInfo m : matches) {
if (!specList.containsKey(m.getId())) {
specList.put(m.getId(), m.getUrl());
}

View File

@ -10,8 +10,6 @@ import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.json.JSONUtil;
import org.hl7.fhir.utilities.json.JsonTrackingParser;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
@ -25,51 +23,6 @@ import java.util.Set;
public class PackageClient {
public class PackageInfo {
private String id;
private String version;
private String fhirVersion;
private String description;
private String url;
private String canonical;
public PackageInfo(String id, String version, String fhirVersion, String description, String url, String canonical) {
super();
this.id = id;
this.version = version;
this.fhirVersion = fhirVersion;
this.description = description;
this.url = url;
if (url == null && id != null && version != null) {
url = Utilities.pathURL(address, id, version);
}
this.canonical = canonical;
}
public String getId() {
return id;
}
public String getVersion() {
return version;
}
public String getFhirVersion() {
return fhirVersion;
}
public String getDescription() {
return description;
}
public String getUrl() {
return url;
}
public String getCanonical() {
return canonical;
}
@Override
public String toString() {
return id+"#"+(version == null ? "?pc-pi?" : version)+(fhirVersion == null ? "": " ("+canonical+") for FHIR "+fhirVersion)+(url == null ? "" : " @"+url)+(description == null ? "" : " '"+description+"'");
}
}
private String address;
private String cacheFolder;
@ -124,7 +77,13 @@ public class PackageClient {
if (versions != null) {
for (String v : sorted(versions.keySet())) {
JsonObject obj = versions.getAsJsonObject(v);
res.add(new PackageInfo(JSONUtil.str(obj, "name"), JSONUtil.str(obj, "version"), JSONUtil.str(obj, "FhirVersion"), JSONUtil.str(obj, "description"), JSONUtil.str(obj, "url"), JSONUtil.str(obj, "canonical")));
res.add(new PackageInfo(JSONUtil.str(obj, "name"),
JSONUtil.str(obj, "version"),
JSONUtil.str(obj, "FhirVersion"),
JSONUtil.str(obj, "description"),
JSONUtil.str(obj, "url"),
JSONUtil.str(obj, "canonical"),
address));
}
}
} catch (FileNotFoundException e) {
@ -158,7 +117,13 @@ public class PackageClient {
JsonArray json = fetchJsonArray(Utilities.pathURL(address, "catalog?")+params.toString());
for (JsonElement e : json) {
JsonObject obj = (JsonObject) e;
res.add(new PackageInfo(JSONUtil.str(obj, "Name", "name"), JSONUtil.str(obj, "Version", "version"), JSONUtil.str(obj, "FhirVersion", "fhirVersion"), JSONUtil.str(obj, "Description", "description"), JSONUtil.str(obj, "url"), JSONUtil.str(obj, "canonical")));
res.add(new PackageInfo(JSONUtil.str(obj, "Name", "name"),
JSONUtil.str(obj, "Version", "version"),
JSONUtil.str(obj, "FhirVersion", "fhirVersion"),
JSONUtil.str(obj, "Description", "description"),
JSONUtil.str(obj, "url"),
JSONUtil.str(obj, "canonical"),
address));
}
} catch (IOException e1) {
}
@ -199,10 +164,10 @@ public class PackageClient {
if (list.isEmpty()) {
throw new IOException("Package not found: "+id);
} else {
String v = list.get(0).version;
String v = list.get(0).getVersion();
for (PackageInfo p : list) {
if (VersionUtilities.isThisOrLater(v, p.version)) {
v = p.version;
if (VersionUtilities.isThisOrLater(v, p.getVersion())) {
v = p.getVersion();
}
}
return v;
@ -216,8 +181,8 @@ public class PackageClient {
} else {
String v = majMinVersion;
for (PackageInfo p : list) {
if (VersionUtilities.isMajMinOrLaterPatch(v, p.version)) {
v = p.version;
if (VersionUtilities.isMajMinOrLaterPatch(v, p.getVersion())) {
v = p.getVersion();
}
}
return v;
@ -259,7 +224,7 @@ public class PackageClient {
}
}
if (version != null) {
result.add(new PackageInfo(id, version, fVersion, description, url, pcanonical));
result.add(new PackageInfo(id, version, fVersion, description, url, pcanonical, address));
}
}
}

View File

@ -35,6 +35,8 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.Arrays;
import java.util.List;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
@ -109,20 +111,29 @@ public class PackageGenerator {
object.addProperty("version", value);
return this;
}
public PackageGenerator toolsVersion(int value) {
object.addProperty("tools-version", value);
return this;
}
public PackageGenerator fhirVersions(List<String> versions) {
JsonArray fhirVersionsArray = new JsonArray();
for (String version : versions) {
fhirVersionsArray.add(version);
}
object.add("fhirVersions", fhirVersionsArray);
return this;
}
public PackageGenerator description(String value) {
object.addProperty("description", value);
return this;
return this;
}
public PackageGenerator license(String value) {
object.addProperty("license", value);
return this;
return this;
}
public PackageGenerator homepage(String value) {

View File

@ -0,0 +1,59 @@
package org.hl7.fhir.utilities.npm;
import org.hl7.fhir.utilities.Utilities;
public class PackageInfo {
private final String id;
private final String version;
private final String fhirVersion;
private final String description;
private final String url;
private final String canonical;
public PackageInfo(String id, String version, String fhirVersion, String description, String url, String canonical) {
this(id, version, fhirVersion, description, url, canonical, null);
}
public PackageInfo(String id, String version, String fhirVersion, String description, String url, String canonical, String address) {
super();
this.id = id;
this.version = version;
this.fhirVersion = fhirVersion;
this.description = description;
if (url == null && id != null && version != null) {
this.url = Utilities.pathURL(address, id, version);
} else {
this.url = url;
}
this.canonical = canonical;
}
public String getId() {
return id;
}
public String getVersion() {
return version;
}
public String getFhirVersion() {
return fhirVersion;
}
public String getDescription() {
return description;
}
public String getUrl() {
return url;
}
public String getCanonical() {
return canonical;
}
@Override
public String toString() {
return id + "#" + (version == null ? "?pc-pi?" : version) + (fhirVersion == null ? "" : " (" + canonical + ") for FHIR " + fhirVersion) + (url == null ? "" : " @" + url) + (description == null ? "" : " '" + description + "'");
}
}

View File

@ -111,7 +111,7 @@ public class XmlGenerator {
}
private void processElement(Element element) throws IOException, FHIRException {
if (!xml.getDefaultNamespace().equals(element.getNamespaceURI()))
if (xml.getDefaultNamespace() == null || !xml.getDefaultNamespace().equals(element.getNamespaceURI()))
xml.setDefaultNamespace(element.getNamespaceURI());
processAttributes(element);

View File

@ -133,9 +133,9 @@ Terminology_TX_Code_ValueSet = No code provided, and a code is required from the
Terminology_TX_Code_ValueSetMax = No code provided, and a code must be provided from the value set {0} (max value set {1})
Terminology_TX_Code_ValueSet_Ext = No code provided, and a code should be provided from the value set {0} ({1})
Terminology_TX_Coding_Count = Expected {0} but found {1} coding elements
Terminology_TX_Confirm_1 = Could not confirm that the codes provided are in the value set {0} and a code from this value set is required (class = {1})
Terminology_TX_Confirm_2 = Could not confirm that the codes provided are in the value set {0} and a code should come from this value set unless it has no suitable code (the validator cannot judge what is suitable) (class = {1})
Terminology_TX_Confirm_3 = Could not confirm that the codes provided are in the value set {0} and a code is recommended to come from this value set (class = {1})
Terminology_TX_Confirm_1_CC = Could not confirm that the codings provided are in the value set {0} and a coding from this value set is required (class = {1})
Terminology_TX_Confirm_2_CC = Could not confirm that the codings provided are in the value set {0} and a coding should come from this value set unless it has no suitable code (the validator cannot judge what is suitable) (class = {1})
Terminology_TX_Confirm_3_CC = Could not confirm that the codings provided are in the value set {0} and a coding is recommended to come from this value set (class = {1})
Terminology_TX_Confirm_4a = The code provided ({2}) is not in the value set {0}, and a code from this value set is required: {1}
Terminology_TX_Confirm_4b = The codes provided ({2}) are not in the value set {0}, and a code from this value set is required: {1}
Terminology_TX_Confirm_5 = Could not confirm that the codes provided are in the value set {0}, and a code should come from this value set unless it has no suitable code (the validator cannot judge what is suitable)
@ -145,18 +145,18 @@ Terminology_TX_Error_CodeableConcept = Error {0} validating CodeableConcept
Terminology_TX_Error_CodeableConcept_Max = Error {0} validating CodeableConcept using maxValueSet
Terminology_TX_Error_Coding1 = Error {0} validating Coding
Terminology_TX_Error_Coding2 = Error {0} validating Coding: {1}
Terminology_TX_NoValid_1 = None of the codes provided are in the value set {0} ({1}), and a code from this value set is required) (codes = {2})
Terminology_TX_NoValid_1_CC = None of the codings provided are in the value set {0} ({1}), and a coding from this value set is required) (codes = {2})
Terminology_TX_NoValid_10 = The code provided is not in the maximum value set {0} ({1}), and a code from this value set is required) (code = {2}#{3})
Terminology_TX_NoValid_11 = The code provided is not in the maximum value set {0} ({1}{2})
Terminology_TX_NoValid_12 = The Coding provided ({2}) is not in the value set {0}, and a code is required from this value set. {1}
Terminology_TX_NoValid_13 = The Coding provided ({2}) is not in the value set {0}, and a code should come from this value set unless it has no suitable code (the validator cannot judge what is suitable). {1}
Terminology_TX_NoValid_13 = The Coding provided ({2}) is not in the value set {0}, and a code should come from this value set unless it has no suitable code (note that the validator cannot judge what is suitable). {1}
Terminology_TX_NoValid_14 = The Coding provided ({2}) is not in the value set {0}, and a code is recommended to come from this value set. {1}
Terminology_TX_NoValid_15 = The value provided (''{0}'') could not be validated in the absence of a terminology server
Terminology_TX_NoValid_16 = The value provided (''{0}'') is not in the value set {1} ({2}), and a code is required from this value set){3}
Terminology_TX_NoValid_17 = The value provided (''{0}'') is not in the value set {1} ({2}), and a code should come from this value set unless it has no suitable code and the validator cannot judge what is suitable) {3}
Terminology_TX_NoValid_17 = The value provided (''{0}'') is not in the value set {1} ({2}), and a code should come from this value set unless it has no suitable code (note that the validator cannot judge what is suitable) {3}
Terminology_TX_NoValid_18 = The value provided (''{0}'') is not in the value set {1} ({2}), and a code is recommended to come from this value set){3}
Terminology_TX_NoValid_2 = None of the codes provided are in the value set {0} ({1}), and a code should come from this value set unless it has no suitable code and the validator cannot judge what is suitable) (codes = {2})
Terminology_TX_NoValid_3 = None of the codes provided are in the value set {0} ({1}), and a code is recommended to come from this value set) (codes = {2})
Terminology_TX_NoValid_2_CC = None of the codings provided are in the value set {0} ({1}), and a coding should come from this value set unless it has no suitable code (note that the validator cannot judge what is suitable) (codes = {2})
Terminology_TX_NoValid_3_CC = None of the codings provided are in the value set {0} ({1}), and a coding is recommended to come from this value set) (codes = {2})
Terminology_TX_NoValid_4 = The Coding provided ({2}) is not in the value set {0}, and a code is required from this value set {1}
Terminology_TX_NoValid_5 = The Coding provided ({2}) is not in the value set {0}, and a code should come from this value set unless it has no suitable code (the validator cannot judge what is suitable) {1}
Terminology_TX_NoValid_6 = The Coding provided ({2}) is not in the value set {0}, and a code is recommended to come from this value set {1}
@ -325,7 +325,7 @@ Adding_wrong_path_in_profile___vs_ = Adding wrong path in profile {0}: {1} vs {2
_has_no_children__and_no_types_in_profile_ = {0} has no children ({1}) and no types in profile {2}
not_done_yet = not done yet
Did_not_find_single_slice_ = Did not find single slice: {0}
Differential_does_not_have_a_slice__b_of_____in_profile_ = Differential does not have a slice: {0}/ (b:{1} of {2} / {3}/ {4}) in profile {5}
Differential_does_not_have_a_slice__b_of_____in_profile_ = Differential in profile {5} does not have a slice at {6} (on {0}, position {1} of {2} / {3} / {4})
Attempt_to_a_slice_an_element_that_does_not_repeat__from__in_ = Attempt to a slice an element that does not repeat: {0}/{1} from {2} in {3}, at element {4} (slice = {5})
Unable_to_resolve_reference_to_ = Unable to resolve reference to {0}
Unable_to_find_element__in_ = Unable to find element {0} in {1}
@ -639,3 +639,5 @@ TYPE_SPECIFIC_CHECKS_DT_CANONICAL_TYPE = Canonical URL ''{0}'' refers to a resou
CODESYSTEM_CS_NO_SUPPLEMENT = CodeSystem {0} is a supplement, so can't be used as a value in Coding.system
CODESYSTEM_CS_SUPP_CANT_CHECK = CodeSystem {0} cannot be found, so can't check if concepts are valid
CODESYSTEM_CS_SUPP_INVALID_CODE = The code ''{1}'' is not declared in the base CodeSystem {0} so is not valid in the supplement
SD_VALUE_TYPE_IILEGAL = The element {0} has a {1} of type {2}, which is not in the list of allowed types ({3})
SD_NO_TYPES_OR_CONTENTREF = The element {0} has no assigned types, and no content reference

View File

@ -128,9 +128,9 @@ Terminology_TX_Code_ValueSet=Es wird kein Code gesetzt, und es ist ein Code aus
Terminology_TX_Code_ValueSetMax=Kein Code gesetzt, und es muss ein Code aus ValueSet {0} (max. Wertemenge {1}) gesetzt werden
Terminology_TX_Code_ValueSet_Ext=Kein Code gesetzt, und es sollte ein Code aus ValueSet{0} ({1}) gesetzt werden
Terminology_TX_Coding_Count=Erwartete {0}, aber gefundene {1} coding elements
Terminology_TX_Confirm_1=Konnte nicht bestätigen, dass die angegebenen Codes im ValueSet {0} enthalten sind und ein Code aus diesem ValueSet ist erforderlich (class = {1})
Terminology_TX_Confirm_2=Konnte nicht bestätigen, dass die angegebenen Codes im ValueSet {0} enthalten sind und ein Code aus diesem ValueSet stammen sollte. Es sei denn, es enthält keinen geeigneten Code (class = {1})
Terminology_TX_Confirm_3=Konnte nicht bestätigen, dass die angegebenen Codes im ValueSet {0} enthalten sind, und es wird empfohlen einen Code aus diesem ValueSet zu verwenden (Klasse = {1})
Terminology_TX_Confirm_1_CC=Konnte nicht bestätigen, dass die angegebenen Codes im ValueSet {0} enthalten sind und ein Code aus diesem ValueSet ist erforderlich (class = {1})
Terminology_TX_Confirm_2_CC=Konnte nicht bestätigen, dass die angegebenen Codes im ValueSet {0} enthalten sind und ein Code aus diesem ValueSet stammen sollte. Es sei denn, es enthält keinen geeigneten Code (class = {1})
Terminology_TX_Confirm_3_CC=Konnte nicht bestätigen, dass die angegebenen Codes im ValueSet {0} enthalten sind, und es wird empfohlen einen Code aus diesem ValueSet zu verwenden (Klasse = {1})
Terminology_TX_Confirm_4=Konnte nicht bestätigen, dass die angegebenen Codes im ValueSet {0} enthalten sind, und ein Code aus diesem ValueSet ist erforderlich
Terminology_TX_Confirm_5=Konnte nicht bestätigen, dass die angegebenen Codes im ValueSet {0} enthalten sind, und ein Code sollte aus diesem ValueSet stammen. Es sei denn, er hat enthält keinen geeigneten Code
Terminology_TX_Confirm_6=Konnte nicht bestätigen, dass die angegebenen Codes im ValueSet {0} enthalten sind, und es wird empfohlen, einen Code aus diesem ValueSet zu verwenden.
@ -139,7 +139,7 @@ Terminology_TX_Error_CodeableConcept=Fehler {0} bei der Validierung des Codeable
Terminology_TX_Error_CodeableConcept_Max=Fehler {0} bei der Validierung des CodeableConcepts mit maxValueSet
Terminology_TX_Error_Coding1=Fehler {0} bei der Validierung des Coding
Terminology_TX_Error_Coding2=Fehler {0} bei der Validierung des Coding: {1}
Terminology_TX_NoValid_1=Keiner der bereitgestellten Codes ist im ValueSet {0} ({1}, und ein Code aus diesem ValueSet ist erforderlich) (Codes = {2})
Terminology_TX_NoValid_1_CC=Keiner der bereitgestellten Codes ist im ValueSet {0} ({1}, und ein Code aus diesem ValueSet ist erforderlich) (Codes = {2})
Terminology_TX_NoValid_10=Der bereitgestellte Code ist nicht im maximum ValueSet {0} ({1}, und ein Code aus diesem ValueSet ist erforderlich) (Code = {2}#{3})
Terminology_TX_NoValid_11=Der bereitgestellte Code ist nicht im maximum value set {0} ({1}{2}
Terminology_TX_NoValid_12=Die angegebene Codierung ist nicht im ValueSet {0} enthalten, und es wird ein Code aus diesem ValueSet benötigt. {1}
@ -149,8 +149,8 @@ Terminology_TX_NoValid_15=Der angegebene Wert ("{0}") konnte in Ermangelung eine
Terminology_TX_NoValid_16=Der angegebene Wert ("{0}") ist nicht im ValueSet {1} ({2}, und ein Code aus diesem Valueset ist erforderlich){3}
Terminology_TX_NoValid_17=Der angegebene Wert ("{0}") ist nicht im Valueset {1} ({2}, und ein Code sollte aus diesem Valueset stammen, es sei denn, er hat enthält geeigneten Code){3}
Terminology_TX_NoValid_18=Der angegebene Wert ("{0}") ist nicht im Valueset {1} ({2}, und es wird empfohlen, einen Code aus diesem Valueset zu verwenden){3}
Terminology_TX_NoValid_2=Keiner der angegebenen Codes ist im Valueset {0} ({1}, und ein Code sollte aus diesem Valueset stammen, es sei denn, er enthält keinen geeigneten Code) (Codes = {2})
Terminology_TX_NoValid_3=Keiner der angegebenen Codes ist im Valueset {0} ({1}, und es wird empfohlen, einen Code aus dieserm Valueset zu verwenden) (Codes = {2})
Terminology_TX_NoValid_2_CC=Keiner der angegebenen Codes ist im Valueset {0} ({1}, und ein Code sollte aus diesem Valueset stammen, es sei denn, er enthält keinen geeigneten Code) (Codes = {2})
Terminology_TX_NoValid_3_CC=Keiner der angegebenen Codes ist im Valueset {0} ({1}, und es wird empfohlen, einen Code aus dieserm Valueset zu verwenden) (Codes = {2})
Terminology_TX_NoValid_4=Die bereitgestellte Codierung ist nicht im Valueset {0}, und es wird ein Code aus diesem Valueset benötigt{1}
Terminology_TX_NoValid_5=Die angegebene Codierung ist nicht im Valueset {0}, und ein Code sollte aus diesem Valueset stammen, es sei denn, er enthält keinen geeigneten Code{1}
Terminology_TX_NoValid_6=Die bereitgestellte Codierung ist nicht im Valueset {0} enthalten, und es wird empfohlen, einen Code aus diesem Valueset zu verwenden{1}

View File

@ -1,7 +1,7 @@
package org.hl7.fhir.utilities.tests;
import org.hl7.fhir.utilities.npm.CachingPackageClient;
import org.hl7.fhir.utilities.npm.PackageClient.PackageInfo;
import org.hl7.fhir.utilities.npm.PackageInfo;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>5.2.21-SNAPSHOT</version>
<version>5.3.7-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>5.2.21-SNAPSHOT</version>
<version>5.3.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -100,6 +100,11 @@
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
<dependency>
<groupId>org.fhir</groupId>
<artifactId>ucum</artifactId>

View File

@ -1,5 +1,6 @@
package org.hl7.fhir.validation;
import com.google.gson.JsonObject;
import lombok.Getter;
import org.hl7.fhir.convertors.*;
import org.hl7.fhir.exceptions.FHIRException;
@ -15,12 +16,15 @@ import org.hl7.fhir.utilities.IniFile;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.json.JSONUtil;
import org.hl7.fhir.utilities.json.JsonTrackingParser;
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
import org.hl7.fhir.utilities.npm.NpmPackage;
import org.hl7.fhir.utilities.turtle.Turtle;
import org.hl7.fhir.utilities.xml.XMLUtil;
import org.hl7.fhir.validation.cli.utils.Common;
import org.hl7.fhir.validation.cli.utils.VersionSourceInformation;
import org.w3c.dom.Document;
import java.io.*;
import java.net.HttpURLConnection;
@ -61,7 +65,7 @@ public class IgLoader {
public void loadIg(List<ImplementationGuide> igs,
Map<String, byte[]> binaries,
String src,
String src,
boolean recursive) throws IOException, FHIRException {
NpmPackage npm = src.matches(FilesystemPackageCacheManager.PACKAGE_VERSION_REGEX_OPT) && !new File(src).exists() ? getPackageCacheManager().loadPackage(src, null) : null;
if (npm != null) {
@ -143,7 +147,7 @@ public class IgLoader {
* @throws IOException
**/
public Map<String, byte[]> loadIgSource(String src,
boolean recursive,
boolean recursive,
boolean explore) throws FHIRException, IOException {
// src can be one of the following:
// - a canonical url for an ig - this will be converted to a package id and loaded into the cache
@ -199,6 +203,43 @@ public class IgLoader {
versions.see(readInfoVersion(source.get("version.info")), "version.info in " + src);
}
public void scanForVersions(List<String> sources, VersionSourceInformation versions) throws FHIRException, IOException {
List<String> refs = new ArrayList<String>();
ValidatorUtils.parseSources(sources, refs, context);
for (String ref : refs) {
Content cnt = loadContent(ref, "validate", false);
String s = TextFile.bytesToString(cnt.focus);
if (s.contains("http://hl7.org/fhir/3.0")) {
versions.see("3.0", "Profile in " + ref);
}
if (s.contains("http://hl7.org/fhir/1.0")) {
versions.see("1.0", "Profile in " + ref);
}
if (s.contains("http://hl7.org/fhir/4.0")) {
versions.see("4.0", "Profile in " + ref);
}
if (s.contains("http://hl7.org/fhir/1.4")) {
versions.see("1.4", "Profile in " + ref);
}
try {
if (s.startsWith("{")) {
JsonObject json = JsonTrackingParser.parse(s, null);
if (json.has("fhirVersion")) {
versions.see(VersionUtilities.getMajMin(JSONUtil.str(json, "fhirVersion")), "fhirVersion in " + ref);
}
} else {
Document doc = ValidatorUtils.parseXml(cnt.focus);
String v = XMLUtil.getNamedChildValue(doc.getDocumentElement(), "fhirVersion");
if (v != null) {
versions.see(VersionUtilities.getMajMin(v), "fhirVersion in " + ref);
}
}
} catch (Exception e) {
// nothing
}
}
}
protected Map<String, byte[]> readZip(InputStream stream) throws IOException {
Map<String, byte[]> res = new HashMap<>();
ZipInputStream zip = new ZipInputStream(stream);
@ -521,7 +562,7 @@ public class IgLoader {
for (File ff : f.listFiles()) {
if (ff.isDirectory() && recursive) {
res.putAll(scanDirectory(ff, true));
} else if (!isIgnoreFile(ff)) {
} else if (!ff.isDirectory() && !isIgnoreFile(ff)) {
Manager.FhirFormat fmt = ResourceChecker.checkIsResource(getContext(), isDebug(), ff.getAbsolutePath());
if (fmt != null) {
res.put(Utilities.changeFileExt(ff.getName(), "." + fmt.getExtension()), TextFile.fileToBytes(ff.getAbsolutePath()));
@ -645,7 +686,7 @@ public class IgLoader {
else if (fn.endsWith(".json") && !fn.endsWith("template.json"))
r = new JsonParser().parse(new ByteArrayInputStream(content));
else if (fn.endsWith(".txt"))
r = new StructureMapUtilities(context, null, null).parse(TextFile.bytesToString(content), fn);
r = new StructureMapUtilities(getContext(), null, null).parse(TextFile.bytesToString(content), fn);
else if (fn.endsWith(".map"))
r = new StructureMapUtilities(null).parse(new String(content), fn);
else

View File

@ -193,49 +193,12 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
igLoader = new IgLoader(getPcm(), getContext(), getVersion(), isDebug());
}
public ValidationEngine(String src, FhirPublication version, String vString, TimeTracker tt) throws FHIRException, IOException, URISyntaxException {
public ValidationEngine(String src, String vString, TimeTracker tt) throws FHIRException, IOException, URISyntaxException {
loadCoreDefinitions(src, false, tt);
setVersion(vString);
igLoader = new IgLoader(getPcm(), getContext(), getVersion(), isDebug());
}
public void scanForVersions(List<String> sources, VersionSourceInformation versions) throws FHIRException, IOException {
List<String> refs = new ArrayList<String>();
ValidatorUtils.parseSources(sources, refs, context);
for (String ref : refs) {
Content cnt = igLoader.loadContent(ref, "validate", false);
String s = TextFile.bytesToString(cnt.focus);
if (s.contains("http://hl7.org/fhir/3.0")) {
versions.see("3.0", "Profile in " + ref);
}
if (s.contains("http://hl7.org/fhir/1.0")) {
versions.see("1.0", "Profile in " + ref);
}
if (s.contains("http://hl7.org/fhir/4.0")) {
versions.see("4.0", "Profile in " + ref);
}
if (s.contains("http://hl7.org/fhir/1.4")) {
versions.see("1.4", "Profile in " + ref);
}
try {
if (s.startsWith("{")) {
JsonObject json = JsonTrackingParser.parse(s, null);
if (json.has("fhirVersion")) {
versions.see(VersionUtilities.getMajMin(JSONUtil.str(json, "fhirVersion")), "fhirVersion in " + ref);
}
} else {
Document doc = ValidatorUtils.parseXml(cnt.focus);
String v = XMLUtil.getNamedChildValue(doc.getDocumentElement(), "fhirVersion");
if (v != null) {
versions.see(VersionUtilities.getMajMin(v), "fhirVersion in " + ref);
}
}
} catch (Exception e) {
// nothing
}
}
}
private void loadCoreDefinitions(String src, boolean recursive, TimeTracker tt) throws FHIRException, IOException {
NpmPackage npm = getPcm().loadPackage(src, null);
if (npm != null) {
@ -252,7 +215,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
initContext(tt);
}
public void initContext(TimeTracker tt) throws IOException, FileNotFoundException {
public void initContext(TimeTracker tt) throws IOException {
context.setCanNoTS(true);
context.setCacheId(UUID.randomUUID().toString());
context.setAllowLoadingDuplicates(true); // because of Forge

View File

@ -94,6 +94,8 @@ public class ValidatorCli {
public static final String JAVA_DISABLED_PROXY_SCHEMES = "jdk.http.auth.proxying.disabledSchemes";
public static final String JAVA_USE_SYSTEM_PROXIES = "java.net.useSystemProxies";
private static ValidationService validationService = new ValidationService();
public static void main(String[] args) throws Exception {
TimeTracker tt = new TimeTracker();
TimeTracker.Session tts = tt.start("Loading");
@ -181,42 +183,42 @@ public class ValidatorCli {
private static void doLeftRightComparison(String[] args, CliContext cliContext, TimeTracker tt) throws Exception {
Display.printCliArgumentsAndInfo(args);
if (cliContext.getSv() == null) {
cliContext.setSv(ValidationService.determineVersion(cliContext));
cliContext.setSv(validationService.determineVersion(cliContext));
}
String v = VersionUtilities.getCurrentVersion(cliContext.getSv());
String definitions = VersionUtilities.packageForVersion(v) + "#" + v;
ValidationEngine validator = ValidationService.getValidator(cliContext, definitions, tt);
ValidationEngine validator = validationService.initializeValidator(cliContext, definitions, tt);
ComparisonService.doLeftRightComparison(args, Params.getParam(args, Params.DESTINATION), validator);
}
private static void doValidation(TimeTracker tt, TimeTracker.Session tts, CliContext cliContext) throws Exception {
if (cliContext.getSv() == null) {
cliContext.setSv(ValidationService.determineVersion(cliContext));
cliContext.setSv(validationService.determineVersion(cliContext));
}
System.out.println("Loading");
// Comment this out because definitions filename doesn't necessarily contain version (and many not even be 14 characters long).
// Version gets spit out a couple of lines later after we've loaded the context
String definitions = VersionUtilities.packageForVersion(cliContext.getSv()) + "#" + VersionUtilities.getCurrentVersion(cliContext.getSv());
ValidationEngine validator = ValidationService.getValidator(cliContext, definitions, tt);
ValidationEngine validator = validationService.initializeValidator(cliContext, definitions, tt);
tts.end();
switch (cliContext.getMode()) {
case TRANSFORM:
ValidationService.transform(cliContext, validator);
validationService.transform(cliContext, validator);
break;
case NARRATIVE:
ValidationService.generateNarrative(cliContext, validator);
validationService.generateNarrative(cliContext, validator);
break;
case SNAPSHOT:
ValidationService.generateSnapshot(cliContext, validator);
validationService.generateSnapshot(cliContext, validator);
break;
case CONVERT:
ValidationService.convertSources(cliContext, validator);
validationService.convertSources(cliContext, validator);
break;
case FHIRPATH:
ValidationService.evaluateFhirpath(cliContext, validator);
validationService.evaluateFhirpath(cliContext, validator);
break;
case VERSION:
ValidationService.transformVersion(cliContext, validator);
validationService.transformVersion(cliContext, validator);
break;
case VALIDATION:
case SCAN:
@ -232,7 +234,7 @@ public class ValidatorCli {
Scanner validationScanner = new Scanner(validator.getContext(), validator.getValidator(), validator.getIgLoader(), validator.getFhirPathEngine());
validationScanner.validateScan(cliContext.getOutput(), cliContext.getSources());
} else {
ValidationService.validateSources(cliContext, validator);
validationService.validateSources(cliContext, validator);
}
break;
}

View File

@ -18,11 +18,19 @@ public class ValidationRequest {
return cliContext;
}
@JsonProperty("sessionId")
public String sessionId;
public ValidationRequest() {}
public ValidationRequest(CliContext cliContext, List<FileInfo> filesToValidate) {
this(cliContext, filesToValidate, null);
}
public ValidationRequest(CliContext cliContext, List<FileInfo> filesToValidate, String sessionToken) {
this.cliContext = cliContext;
this.filesToValidate = filesToValidate;
this.sessionId = sessionToken;
}
@JsonProperty("cliContext")
@ -42,6 +50,17 @@ public class ValidationRequest {
return this;
}
@JsonProperty("sessionId")
public String getSessionId() {
return sessionId;
}
@JsonProperty("sessionId")
public ValidationRequest setSessionId(String sessionId) {
this.sessionId = sessionId;
return this;
}
public String listSourceFiles() {
List<String> fileNames = new ArrayList<>();
for (FileInfo fp : filesToValidate) {

View File

@ -10,10 +10,18 @@ public class ValidationResponse {
@JsonProperty("outcomes")
public List<ValidationOutcome> outcomes = new ArrayList<>();
@JsonProperty("sessionId")
public String sessionId;
public ValidationResponse() {}
public ValidationResponse(List<ValidationOutcome> outcomes) {
this(outcomes, null);
}
public ValidationResponse(List<ValidationOutcome> outcomes, String sessionId) {
this.outcomes = outcomes;
this.sessionId = sessionId;
}
@JsonProperty("outcomes")
@ -27,6 +35,17 @@ public class ValidationResponse {
return this;
}
@JsonProperty("sessionId")
public String getSessionId() {
return sessionId;
}
@JsonProperty("sessionId")
public ValidationResponse setSessionId(String sessionId) {
this.sessionId = sessionId;
return this;
}
public ValidationResponse addOutcome(ValidationOutcome outcome) {
if (outcomes == null) {
outcomes = new ArrayList<>();

View File

@ -0,0 +1,95 @@
package org.hl7.fhir.validation.cli.services;
import org.apache.commons.collections4.map.PassiveExpiringMap;
import org.hl7.fhir.validation.ValidationEngine;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* SessionCache for storing and retrieving ValidationEngine instances, so callers do not have to re-instantiate a new
* instance for each validation request.
*/
public class SessionCache {
protected static final long TIME_TO_LIVE = 60;
protected static final TimeUnit TIME_UNIT = TimeUnit.MINUTES;
private final PassiveExpiringMap<String, ValidationEngine> cachedSessions;
public SessionCache() {
cachedSessions = new PassiveExpiringMap<>(TIME_TO_LIVE, TIME_UNIT);
}
/**
* @param sessionLength the constant amount of time an entry is available before it expires. A negative value results
* in entries that NEVER expire. A zero value results in entries that ALWAYS expire.
* @param sessionLengthUnit the unit of time for the timeToLive parameter, must not be null
*/
public SessionCache(long sessionLength, TimeUnit sessionLengthUnit) {
cachedSessions = new PassiveExpiringMap<>(sessionLength, sessionLengthUnit);
}
/**
* Stores the initialized {@link ValidationEngine} in the cache. Returns the session id that will be associated with
* this instance.
* @param validationEngine {@link ValidationEngine}
* @return The {@link String} id associated with the stored instance.
*/
public String cacheSession(ValidationEngine validationEngine) {
String generatedId = generateID();
cachedSessions.put(generatedId, validationEngine);
return generatedId;
}
/**
* Stores the initialized {@link ValidationEngine} in the cache with the passed in id as the key. If a null key is
* passed in, a new key is generated and returned.
* @param sessionId The {@link String} key to associate with this stored {@link ValidationEngine}
* @param validationEngine The {@link ValidationEngine} instance to cache.
* @return The {@link String} id that will be associated with the stored {@link ValidationEngine}
*/
public String cacheSession(String sessionId, ValidationEngine validationEngine) {
if(sessionId == null) {
sessionId = cacheSession(validationEngine);
} else {
cachedSessions.put(sessionId, validationEngine);
}
return sessionId;
}
/**
* Checks if the passed in {@link String} id exists in the set of stored session id.
* @param sessionId The {@link String} id to search for.
* @return {@link Boolean#TRUE} if such id exists.
*/
public boolean sessionExists(String sessionId) {
return cachedSessions.containsKey(sessionId);
}
/**
* Returns the stored {@link ValidationEngine} associated with the passed in session id, if one such instance exists.
* @param sessionId The {@link String} session id.
* @return The {@link ValidationEngine} associated with the passed in id, or null if none exists.
*/
public ValidationEngine fetchSessionValidatorEngine(String sessionId) {
return cachedSessions.get(sessionId);
}
/**
* Returns the set of stored session ids.
* @return {@link Set} of session ids.
*/
public Set<String> getSessionIds() {
return cachedSessions.keySet();
}
/**
* Session ids generated internally are UUID {@link String}.
* @return A new {@link String} session id.
*/
private String generateID() {
return UUID.randomUUID().toString();
}
}

View File

@ -1,26 +1,20 @@
package org.hl7.fhir.validation.cli.services;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
import org.hl7.fhir.r5.context.SimpleWorkerContext;
import org.hl7.fhir.r5.context.TerminologyCache;
import org.hl7.fhir.r5.elementmodel.Manager;
import org.hl7.fhir.r5.formats.IParser;
import org.hl7.fhir.r5.formats.JsonParser;
import org.hl7.fhir.r5.formats.XmlParser;
import org.hl7.fhir.r5.model.Bundle;
import org.hl7.fhir.r5.model.DomainResource;
import org.hl7.fhir.r5.model.FhirPublication;
import org.hl7.fhir.r5.model.OperationOutcome;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.*;
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.TimeTracker;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
import org.hl7.fhir.utilities.npm.ToolsVersion;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.validation.IgLoader;
import org.hl7.fhir.validation.ValidationEngine;
@ -29,14 +23,32 @@ import org.hl7.fhir.validation.cli.model.*;
import org.hl7.fhir.validation.cli.utils.EngineMode;
import org.hl7.fhir.validation.cli.utils.VersionSourceInformation;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
public class ValidationService {
public static ValidationResponse validateSources(ValidationRequest request) throws Exception {
private final SessionCache sessionCache;
public ValidationService() {
sessionCache = new SessionCache();
}
protected ValidationService(SessionCache cache) {
this.sessionCache = cache;
}
public ValidationResponse validateSources(ValidationRequest request) throws Exception {
if (request.getCliContext().getSv() == null) {
request.getCliContext().setSv(ValidationService.determineVersion(request.getCliContext()));
String sv = determineVersion(request.getCliContext(), request.sessionId);
request.getCliContext().setSv(sv);
}
String definitions = VersionUtilities.packageForVersion(request.getCliContext().getSv()) + "#" + VersionUtilities.getCurrentVersion(request.getCliContext().getSv());
ValidationEngine validator = ValidationService.getValidator(request.getCliContext(), definitions, new TimeTracker());
String sessionId = initializeValidator(request.getCliContext(), definitions, new TimeTracker(), request.sessionId);
ValidationEngine validator = sessionCache.fetchSessionValidatorEngine(sessionId);
if (request.getCliContext().getProfiles().size() > 0) {
System.out.println(" .. validate " + request.listSourceFiles() + " against " + request.getCliContext().getProfiles().toString());
@ -44,7 +56,8 @@ public class ValidationService {
System.out.println(" .. validate " + request.listSourceFiles());
}
ValidationResponse response = new ValidationResponse();
ValidationResponse response = new ValidationResponse().setSessionId(sessionId);
for (FileInfo fp : request.getFilesToValidate()) {
List<ValidationMessage> messages = new ArrayList<>();
validator.validate(fp.getFileContent().getBytes(), Manager.FhirFormat.getFhirFormat(fp.getFileType()),
@ -56,23 +69,25 @@ public class ValidationService {
return response;
}
public static VersionSourceInformation scanForVersions(CliContext cliContext) throws Exception {
public VersionSourceInformation scanForVersions(CliContext cliContext) throws Exception {
VersionSourceInformation versions = new VersionSourceInformation();
ValidationEngine ve = new ValidationEngine();
IgLoader igLoader = new IgLoader(ve.getPcm(), ve.getContext(), ve.getVersion(), ve.isDebug());
IgLoader igLoader = new IgLoader(
new FilesystemPackageCacheManager(true, ToolsVersion.TOOLS_VERSION),
SimpleWorkerContext.fromNothing(),
null);
for (String src : cliContext.getIgs()) {
igLoader.scanForIgVersion(src, cliContext.isRecursive(), versions);
}
ve.scanForVersions(cliContext.getSources(), versions);
igLoader.scanForVersions(cliContext.getSources(), versions);
return versions;
}
public static void validateSources(CliContext cliContext, ValidationEngine validator) throws Exception {
public void validateSources(CliContext cliContext, ValidationEngine validator) throws Exception {
long start = System.currentTimeMillis();
List<ValidationRecord> records = new ArrayList<>();
Resource r = validator.validate(cliContext.getSources(), cliContext.getProfiles(), records);
int ec = 0;
System.out.println("Done. "+validator.getContext().clock().report());
System.out.println("Done. " + validator.getContext().clock().report());
System.out.println();
if (cliContext.getOutput() == null) {
@ -98,24 +113,24 @@ public class ValidationService {
s.close();
}
if (cliContext.getHtmlOutput() != null) {
String html = new HTMLOutputGenerator(records).generate(System.currentTimeMillis()-start);
String html = new HTMLOutputGenerator(records).generate(System.currentTimeMillis() - start);
TextFile.stringToFile(html, cliContext.getHtmlOutput());
System.out.println("HTML Summary in "+cliContext.getHtmlOutput());
System.out.println("HTML Summary in " + cliContext.getHtmlOutput());
}
System.exit(ec > 0 ? 1 : 0);
}
public static void convertSources(CliContext cliContext, ValidationEngine validator) throws Exception {
public void convertSources(CliContext cliContext, ValidationEngine validator) throws Exception {
System.out.println(" ...convert");
validator.convert(cliContext.getSources().get(0), cliContext.getOutput());
}
public static void evaluateFhirpath(CliContext cliContext, ValidationEngine validator) throws Exception {
public void evaluateFhirpath(CliContext cliContext, ValidationEngine validator) throws Exception {
System.out.println(" ...evaluating " + cliContext.getFhirpath());
System.out.println(validator.evaluateFhirPath(cliContext.getSources().get(0), cliContext.getFhirpath()));
}
public static void generateSnapshot(CliContext cliContext, ValidationEngine validator) throws Exception {
public void generateSnapshot(CliContext cliContext, ValidationEngine validator) throws Exception {
StructureDefinition r = validator.snapshot(cliContext.getSources().get(0), cliContext.getSv());
System.out.println(" ...generated snapshot successfully");
if (cliContext.getOutput() != null) {
@ -123,7 +138,7 @@ public class ValidationService {
}
}
public static void generateNarrative(CliContext cliContext, ValidationEngine validator) throws Exception {
public void generateNarrative(CliContext cliContext, ValidationEngine validator) throws Exception {
DomainResource r = validator.generate(cliContext.getSources().get(0), cliContext.getSv());
System.out.println(" ...generated narrative successfully");
if (cliContext.getOutput() != null) {
@ -131,7 +146,7 @@ public class ValidationService {
}
}
public static void transform(CliContext cliContext, ValidationEngine validator) throws Exception {
public void transform(CliContext cliContext, ValidationEngine validator) throws Exception {
if (cliContext.getSources().size() > 1)
throw new Exception("Can only have one source when doing a transform (found " + cliContext.getSources() + ")");
if (cliContext.getTxServer() == null)
@ -166,7 +181,7 @@ public class ValidationService {
}
}
public static void transformVersion(CliContext cliContext, ValidationEngine validator) throws Exception {
public void transformVersion(CliContext cliContext, ValidationEngine validator) throws Exception {
if (cliContext.getSources().size() > 1) {
throw new Exception("Can only have one source when converting versions (found " + cliContext.getSources() + ")");
}
@ -189,44 +204,54 @@ public class ValidationService {
}
}
public static ValidationEngine getValidator(CliContext cliContext, String definitions, TimeTracker tt) throws Exception {
tt.milestone();
System.out.print(" Load FHIR v" + cliContext.getSv() + " from " + definitions);
FhirPublication ver = FhirPublication.fromCode(cliContext.getSv());
ValidationEngine validator = new ValidationEngine(definitions, ver, cliContext.getSv(), tt);
IgLoader igLoader = new IgLoader(validator.getPcm(), validator.getContext(), validator.getVersion(), validator.isDebug());
System.out.println(" - "+validator.getContext().countAllCaches()+" resources ("+tt.milestone()+")");
igLoader.loadIg(validator.getIgs(), validator.getBinaries(), "hl7.terminology", false);
System.out.print(" Terminology server " + cliContext.getTxServer());
String txver = validator.setTerminologyServer(cliContext.getTxServer(), cliContext.getTxLog(), ver);
System.out.println(" - Version "+txver+" ("+tt.milestone()+")");
validator.setDebug(cliContext.isDoDebug());
for (String src : cliContext.getIgs()) {
igLoader.loadIg(validator.getIgs(), validator.getBinaries(), src, cliContext.isRecursive());
}
System.out.print(" Get set... ");
validator.setQuestionnaireMode(cliContext.getQuestionnaireMode());
validator.setDoNative(cliContext.isDoNative());
validator.setHintAboutNonMustSupport(cliContext.isHintAboutNonMustSupport());
validator.setAnyExtensionsAllowed(cliContext.isAnyExtensionsAllowed());
validator.setLanguage(cliContext.getLang());
validator.setLocale(cliContext.getLocale());
validator.setSnomedExtension(cliContext.getSnomedCTCode());
validator.setAssumeValidRestReferences(cliContext.isAssumeValidRestReferences());
validator.setNoExtensibleBindingMessages(cliContext.isNoExtensibleBindingMessages());
validator.setSecurityChecks(cliContext.isSecurityChecks());
validator.setCrumbTrails(cliContext.isCrumbTrails());
validator.setShowTimes(cliContext.isShowTimes());
validator.setFetcher(new StandAloneValidatorFetcher(validator.getPcm(), validator.getContext(), validator));
validator.getBundleValidationRules().addAll(cliContext.getBundleValidationRules());
TerminologyCache.setNoCaching(cliContext.isNoInternalCaching());
validator.prepare(); // generate any missing snapshots
System.out.println(" go ("+tt.milestone()+")");
return validator;
public ValidationEngine initializeValidator(CliContext cliContext, String definitions, TimeTracker tt) throws Exception {
return sessionCache.fetchSessionValidatorEngine(initializeValidator(cliContext, definitions, tt, null));
}
public static int displayOperationOutcome(OperationOutcome oo, boolean hasMultiples) {
public String initializeValidator(CliContext cliContext, String definitions, TimeTracker tt, String sessionId) throws Exception {
tt.milestone();
if (!sessionCache.sessionExists(sessionId)) {
System.out.println("No such cached session exists for session id " + sessionId + ", re-instantiating validator.");
System.out.print(" Load FHIR v" + cliContext.getSv() + " from " + definitions);
ValidationEngine validator = new ValidationEngine(definitions, cliContext.getSv(), tt);
sessionId = sessionCache.cacheSession(validator);
FhirPublication ver = FhirPublication.fromCode(cliContext.getSv());
IgLoader igLoader = new IgLoader(validator.getPcm(), validator.getContext(), validator.getVersion(), validator.isDebug());
System.out.println(" - " + validator.getContext().countAllCaches() + " resources (" + tt.milestone() + ")");
igLoader.loadIg(validator.getIgs(), validator.getBinaries(), "hl7.terminology", false);
System.out.print(" Terminology server " + cliContext.getTxServer());
String txver = validator.setTerminologyServer(cliContext.getTxServer(), cliContext.getTxLog(), ver);
System.out.println(" - Version " + txver + " (" + tt.milestone() + ")");
validator.setDebug(cliContext.isDoDebug());
for (String src : cliContext.getIgs()) {
igLoader.loadIg(validator.getIgs(), validator.getBinaries(), src, cliContext.isRecursive());
}
System.out.print(" Get set... ");
validator.setQuestionnaireMode(cliContext.getQuestionnaireMode());
validator.setDoNative(cliContext.isDoNative());
validator.setHintAboutNonMustSupport(cliContext.isHintAboutNonMustSupport());
validator.setAnyExtensionsAllowed(cliContext.isAnyExtensionsAllowed());
validator.setLanguage(cliContext.getLang());
validator.setLocale(cliContext.getLocale());
validator.setSnomedExtension(cliContext.getSnomedCTCode());
validator.setAssumeValidRestReferences(cliContext.isAssumeValidRestReferences());
validator.setNoExtensibleBindingMessages(cliContext.isNoExtensibleBindingMessages());
validator.setSecurityChecks(cliContext.isSecurityChecks());
validator.setCrumbTrails(cliContext.isCrumbTrails());
validator.setShowTimes(cliContext.isShowTimes());
validator.setFetcher(new StandAloneValidatorFetcher(validator.getPcm(), validator.getContext(), validator));
validator.getBundleValidationRules().addAll(cliContext.getBundleValidationRules());
TerminologyCache.setNoCaching(cliContext.isNoInternalCaching());
validator.prepare(); // generate any missing snapshots
System.out.println(" go (" + tt.milestone() + ")");
} else {
System.out.println("Cached session exists for session id " + sessionId + ", returning stored validator session id.");
}
return sessionId;
}
public int displayOperationOutcome(OperationOutcome oo, boolean hasMultiples) {
int error = 0;
int warn = 0;
int info = 0;
@ -240,29 +265,29 @@ public class ValidationService {
else
info++;
}
if (hasMultiples) {
System.out.print("-- ");
System.out.print(file);
System.out.print(" --");
System.out.println(Utilities.padLeft("", '-', Integer.max(38, file.length()+6)));
System.out.println(Utilities.padLeft("", '-', Integer.max(38, file.length() + 6)));
}
System.out.println((error == 0 ? "Success" : "*FAILURE*") + ": " + Integer.toString(error) + " errors, " + Integer.toString(warn) + " warnings, " + Integer.toString(info)+" notes");
System.out.println((error == 0 ? "Success" : "*FAILURE*") + ": " + Integer.toString(error) + " errors, " + Integer.toString(warn) + " warnings, " + Integer.toString(info) + " notes");
for (OperationOutcome.OperationOutcomeIssueComponent issue : oo.getIssue()) {
System.out.println(getIssueSummary(issue));
}
if (hasMultiples) {
System.out.print("---");
System.out.print(Utilities.padLeft("", '-', file.length()));
System.out.print(Utilities.padLeft("", '-', file.length()));
System.out.print("---");
System.out.println(Utilities.padLeft("", '-', Integer.max(38, file.length()+6)));
System.out.println(Utilities.padLeft("", '-', Integer.max(38, file.length() + 6)));
System.out.println();
}
return error;
}
private static String getIssueSummary(OperationOutcome.OperationOutcomeIssueComponent issue) {
String loc = null;
private String getIssueSummary(OperationOutcome.OperationOutcomeIssueComponent issue) {
String loc;
if (issue.hasExpression()) {
int line = ToolingExtensions.readIntegerExtension(issue, ToolingExtensions.EXT_ISSUE_LINE, -1);
int col = ToolingExtensions.readIntegerExtension(issue, ToolingExtensions.EXT_ISSUE_COL, -1);
@ -277,12 +302,16 @@ public class ValidationService {
return " " + issue.getSeverity().getDisplay() + " @ " + loc + " : " + issue.getDetails().getText();
}
public static String determineVersion(CliContext cliContext) throws Exception {
public String determineVersion(CliContext cliContext) throws Exception {
return determineVersion(cliContext, null);
}
public String determineVersion(CliContext cliContext, String sessionId) throws Exception {
if (cliContext.getMode() != EngineMode.VALIDATION) {
return "current";
}
System.out.println("Scanning for versions (no -version parameter):");
VersionSourceInformation versions = ValidationService.scanForVersions(cliContext);
VersionSourceInformation versions = scanForVersions(cliContext);
for (String s : versions.getReport()) {
if (!s.equals("(nothing found)")) {
System.out.println(" " + s);

View File

@ -87,7 +87,7 @@ public class Common {
public static ValidationEngine getValidationEngine(String version, String txServer, String definitions, String txLog, TimeTracker tt) throws Exception {
System.out.println("Loading (v = " + version + ", tx server -> " + txServer + ")");
ValidationEngine ve = new ValidationEngine(definitions, FhirPublication.fromCode(version), version, tt);
ValidationEngine ve = new ValidationEngine(definitions, version, tt);
ve.connectToTSServer(txServer, txLog, FhirPublication.fromCode(version));
return ve;
}

View File

@ -8,8 +8,8 @@ import java.util.List;
public class VersionSourceInformation {
private List<String> report = new ArrayList<>();
private List<String> versions = new ArrayList<>();
private final List<String> report = new ArrayList<>();
private final List<String> versions = new ArrayList<>();
public void see(String version, String src) {
version = VersionUtilities.getMajMin(version);

View File

@ -1023,28 +1023,28 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
} else if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure()) {
if (binding.getStrength() == BindingStrength.REQUIRED)
txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_1, describeReference(binding.getValueSet()), vr.getErrorClass().toString());
txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_1_CC, describeReference(binding.getValueSet()), vr.getErrorClass().toString());
else if (binding.getStrength() == BindingStrength.EXTENSIBLE) {
if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"))
checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"), cc, stack);
else if (!noExtensibleWarnings)
txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_2, describeReference(binding.getValueSet()), vr.getErrorClass().toString());
txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_2_CC, describeReference(binding.getValueSet()), vr.getErrorClass().toString());
} else if (binding.getStrength() == BindingStrength.PREFERRED) {
if (baseOnly) {
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_3, describeReference(binding.getValueSet()), vr.getErrorClass().toString());
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_3_CC, describeReference(binding.getValueSet()), vr.getErrorClass().toString());
}
}
} else {
if (binding.getStrength() == BindingStrength.REQUIRED)
txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_1, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc));
else if (binding.getStrength() == BindingStrength.EXTENSIBLE) {
if (binding.getStrength() == BindingStrength.REQUIRED) {
txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_1_CC, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc));
} else if (binding.getStrength() == BindingStrength.EXTENSIBLE) {
if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"))
checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"), cc, stack);
if (!noExtensibleWarnings)
txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_2, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc));
txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_2_CC, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc));
} else if (binding.getStrength() == BindingStrength.PREFERRED) {
if (baseOnly) {
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_3, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc));
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_3_CC, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc));
}
}
}
@ -1137,28 +1137,28 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
bindingsOk = false;
if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure()) {
if (binding.getStrength() == BindingStrength.REQUIRED)
txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_1, describeReference(binding.getValueSet()), vr.getErrorClass().toString());
txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_1_CC, describeReference(binding.getValueSet()), vr.getErrorClass().toString());
else if (binding.getStrength() == BindingStrength.EXTENSIBLE) {
if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"))
checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"), cc, stack);
else if (!noExtensibleWarnings)
txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_2, describeReference(binding.getValueSet()), vr.getErrorClass().toString());
txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_2_CC, describeReference(binding.getValueSet()), vr.getErrorClass().toString());
} else if (binding.getStrength() == BindingStrength.PREFERRED) {
if (baseOnly) {
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_3, describeReference(binding.getValueSet()), vr.getErrorClass().toString());
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_3_CC, describeReference(binding.getValueSet()), vr.getErrorClass().toString());
}
}
} else {
if (binding.getStrength() == BindingStrength.REQUIRED)
txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_1, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc));
txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_1_CC, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc));
else if (binding.getStrength() == BindingStrength.EXTENSIBLE) {
if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"))
checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"), cc, stack);
if (!noExtensibleWarnings)
txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_2, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc));
txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_2_CC, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc));
} else if (binding.getStrength() == BindingStrength.PREFERRED) {
if (baseOnly) {
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_3, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc));
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_3_CC, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc));
}
}
}
@ -2220,6 +2220,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
* 2. This code doesn't actually decode, which is much easier on memory use for big payloads
*/
private boolean isValidBase64(String theEncoded) {
if (theEncoded == null) {
return false;
}
int charCount = 0;
boolean ok = true;
for (int i = 0; i < theEncoded.length(); i++) {
@ -4678,8 +4681,11 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (ed.getMin() > 0) {
if (problematicPaths.contains(ed.getPath()))
hint(errors, IssueType.NOTSUPPORTED, element.line(), element.col(), stack.getLiteralPath(), count >= ed.getMin(), I18nConstants.VALIDATION_VAL_PROFILE_NOCHECKMIN, profile.getUrl(), ed.getPath(), ed.getId(), ed.getSliceName(),ed.getLabel(), stack.getLiteralPath(), Integer.toString(ed.getMin()));
else
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), stack.getLiteralPath(), count >= ed.getMin(), I18nConstants.VALIDATION_VAL_PROFILE_MINIMUM, profile.getUrl(), ed.getPath(), ed.getId(), ed.getSliceName(),ed.getLabel(), stack.getLiteralPath(), Integer.toString(ed.getMin()), Integer.toString(count));
else {
if (count < ed.getMin()) {
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.VALIDATION_VAL_PROFILE_MINIMUM, profile.getUrl(), ed.getPath(), ed.getId(), ed.getSliceName(),ed.getLabel(), stack.getLiteralPath(), Integer.toString(ed.getMin()), Integer.toString(count));
}
}
}
if (ed.hasMax() && !ed.getMax().equals("*")) {
if (problematicPaths.contains(ed.getPath()))

View File

@ -146,6 +146,31 @@ public class StructureDefinitionValidator extends BaseValidator {
// String bt = boundType(typeCodes);
// hint(errors, IssueType.BUSINESSRULE, stack.getLiteralPath(), !snapshot || bt == null, I18nConstants.SD_ED_SHOULD_BIND, element.getNamedChildValue("path"), bt);
}
// in a snapshot, we validate that fixedValue, pattern, and defaultValue, if present, are all of the right type
if (snapshot && element.getIdBase().contains(".")) {
if (rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), !typeCodes.isEmpty() || element.hasChild("contentReference"), I18nConstants.SD_NO_TYPES_OR_CONTENTREF, element.getIdBase())) {
/*
TODO Grahame, this is breaking the ig publisher for implementers
https://chat.fhir.org/#narrow/stream/215610-shorthand/topic/The.20element.20Extension.2Eurl.20has.20a.20fixed.20of.20type.20uri
https://chat.fhir.org/#narrow/stream/179252-IG-creation/topic/BUG.3A.20The.20element.20Extension.2Eurl.20has.20a.20fixed.20of.20type.20uri
https://github.com/HL7/fhir-ig-publisher/issues/240
This was brought up to Wayne, so I'm commenting it out for now. When you get back we can discuss how to
put the changes back in.
*/
// Element v = element.getNamedChild("defaultValue");
// if (v != null) {
// rule(errors, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), typeCodes.contains(v.fhirType()), I18nConstants.SD_VALUE_TYPE_IILEGAL, element.getIdBase(), "defaultValue", v.fhirType(), typeCodes);
// }
// v = element.getNamedChild("fixed");
// if (v != null) {
// rule(errors, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), typeCodes.contains(v.fhirType()), I18nConstants.SD_VALUE_TYPE_IILEGAL, element.getIdBase(), "fixed", v.fhirType(), typeCodes);
// }
// v = element.getNamedChild("pattern");
// if (v != null) {
// rule(errors, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), typeCodes.contains(v.fhirType()), I18nConstants.SD_VALUE_TYPE_IILEGAL, element.getIdBase(), "pattern", v.fhirType(), typeCodes);
// }
}
}
}
private String boundType(Set<String> typeCodes) {
@ -166,6 +191,12 @@ public class StructureDefinitionValidator extends BaseValidator {
if (Utilities.existsInList(tc, "string", "uri", "CodeableConcept", "Quantity", "CodeableReference")) {
return tc;
}
StructureDefinition sd = context.fetchTypeDefinition(tc);
if (sd != null) {
if (sd.hasExtension(ToolingExtensions.EXT_BINDING_METHOD)) {
return tc;
}
}
}
return null;
}

View File

@ -10,7 +10,7 @@ import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.npm.CachingPackageClient;
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
import org.hl7.fhir.utilities.npm.NpmPackage;
import org.hl7.fhir.utilities.npm.PackageClient.PackageInfo;
import org.hl7.fhir.utilities.npm.PackageInfo;
import org.hl7.fhir.utilities.npm.ToolsVersion;
public class PackageValidator {

View File

@ -0,0 +1,51 @@
package org.hl7.fhir.validation.cli.services;
import org.hl7.fhir.validation.ValidationEngine;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
class SessionCacheTest {
@Test
@DisplayName("test session expiration works")
void expiredSession() throws IOException, InterruptedException {
final long EXPIRE_TIME = 5L;
SessionCache cache = new SessionCache(EXPIRE_TIME, TimeUnit.SECONDS);
ValidationEngine testEngine = new ValidationEngine();
String sessionId = cache.cacheSession(testEngine);
TimeUnit.SECONDS.sleep(EXPIRE_TIME + 1L);
Assertions.assertNull(cache.fetchSessionValidatorEngine(sessionId));
}
@Test
@DisplayName("test session caching works")
void cachedSession() throws IOException {
final long EXPIRE_TIME = 5L;
SessionCache cache = new SessionCache(EXPIRE_TIME, TimeUnit.SECONDS);
ValidationEngine testEngine = new ValidationEngine();
String sessionId = cache.cacheSession(testEngine);
Assertions.assertEquals(testEngine, cache.fetchSessionValidatorEngine(sessionId));
}
@Test
@DisplayName("test session exists")
void sessionExists() throws IOException {
SessionCache cache = new SessionCache();
ValidationEngine testEngine = new ValidationEngine();
String sessionId = cache.cacheSession(testEngine);
Assertions.assertTrue(cache.sessionExists(sessionId));
Assertions.assertFalse(cache.sessionExists(UUID.randomUUID().toString()));
}
@Test
@DisplayName("test null session test id returns false")
void testNullSessionExists() {
SessionCache cache = new SessionCache();
Assertions.assertFalse(cache.sessionExists(null));
}
}

View File

@ -0,0 +1,67 @@
package org.hl7.fhir.validation.cli.services;
import org.apache.commons.io.Charsets;
import org.apache.commons.io.IOUtils;
import org.hl7.fhir.r5.elementmodel.Manager;
import org.hl7.fhir.validation.ValidationEngine;
import org.hl7.fhir.validation.cli.model.CliContext;
import org.hl7.fhir.validation.cli.model.FileInfo;
import org.hl7.fhir.validation.cli.model.ValidationRequest;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentMatchers;
import org.mockito.Mockito;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.*;
class ValidationServiceTest {
@Test
void validateSources() throws Exception {
SessionCache sessionCache = Mockito.spy(new SessionCache());
ValidationService myService = new ValidationService(sessionCache);
String resource = IOUtils.toString(getFileFromResourceAsStream("detected_issues.json"), StandardCharsets.UTF_8);
List<FileInfo> filesToValidate = new ArrayList<>();
filesToValidate.add(new FileInfo().setFileName("test_resource.json").setFileContent(resource).setFileType(Manager.FhirFormat.JSON.getExtension()));
ValidationRequest request = new ValidationRequest().setCliContext(new CliContext()).setFilesToValidate(filesToValidate);
// Validation run 1...nothing cached yet
myService.validateSources(request);
Mockito.verify(sessionCache, Mockito.times(1)).cacheSession(ArgumentMatchers.any(ValidationEngine.class));
Set<String> sessionIds = sessionCache.getSessionIds();
if (sessionIds.stream().findFirst().isPresent()) {
// Verify that after 1 run there is only one entry within the cache
Assertions.assertEquals(1, sessionIds.size());
myService.validateSources(request);
// Verify that the cache has been called on once with the id created in the first run
Mockito.verify(sessionCache, Mockito.times(1)).fetchSessionValidatorEngine(sessionIds.stream().findFirst().get());
} else {
// If no sessions exist within the cache after a run, we auto-fail.
fail();
}
}
private InputStream getFileFromResourceAsStream(String fileName) {
// The class loader that loaded the class
ClassLoader classLoader = getClass().getClassLoader();
InputStream inputStream = classLoader.getResourceAsStream(fileName);
// the stream holding the file content
if (inputStream == null) {
throw new IllegalArgumentException("file not found! " + fileName);
} else {
return inputStream;
}
}
}

View File

@ -0,0 +1,18 @@
{
"resourceType": "DetectedIssue",
"identifier": [ {
"system": "http://covidcare.au/app/checkin",
"value": "7"
} ],
"status": "final",
"patient": "Patient/4912",
"identifiedDateTime": "3020-10-27T13:33:15+11:00",
"code": {
"coding": [ {
"system": "http://covidcare.au/app/alert",
"code": "trendNegative",
"display": "CovidCare: Vital signs trend negative alert: re-check recommended"
} ],
"text": "CovidCare alert"
}
}

25
pom.xml
View File

@ -14,13 +14,14 @@
HAPI FHIR
-->
<artifactId>org.hl7.fhir.core</artifactId>
<version>5.2.21-SNAPSHOT</version>
<version>5.3.7-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<hapi_fhir_version>5.1.0</hapi_fhir_version>
<validator_test_case_version>1.1.57-SNAPSHOT</validator_test_case_version>
<junit_jupiter_version>5.6.2</junit_jupiter_version>
<validator_test_case_version>1.1.58-SNAPSHOT</validator_test_case_version>
<junit_jupiter_version>5.7.1</junit_jupiter_version>
<junit_platform_launcher_version>1.7.1</junit_platform_launcher_version>
<maven_surefire_version>3.0.0-M4</maven_surefire_version>
<jacoco_version>0.8.5</jacoco_version>
<info_cqframework_version>1.5.1</info_cqframework_version>
@ -125,6 +126,24 @@
<artifactId>txtmark</artifactId>
<version>0.13</version>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>${junit_platform_launcher_version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit_jupiter_version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>${junit_jupiter_version}</artifactId>
<version>5.7.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>