diff --git a/examples/src/main/java/example/ConverterExamples.java b/examples/src/main/java/example/ConverterExamples.java index 219b59f7a22..710e8338485 100644 --- a/examples/src/main/java/example/ConverterExamples.java +++ b/examples/src/main/java/example/ConverterExamples.java @@ -1,7 +1,7 @@ package example; -import org.hl7.fhir.converter.NullVersionConverterAdvisor30; -import org.hl7.fhir.convertors.*; +import org.hl7.fhir.convertors.conv10_30.Observation10_30; +import org.hl7.fhir.convertors.conv14_30.Questionnaire14_30; import org.hl7.fhir.exceptions.FHIRException; public class ConverterExamples { @@ -9,16 +9,12 @@ public class ConverterExamples { @SuppressWarnings("unused") public void c1020() throws FHIRException { //START SNIPPET: 1020 - // Create a converter - NullVersionConverterAdvisor30 advisor = new NullVersionConverterAdvisor30(); - VersionConvertor_10_30 converter = new VersionConvertor_10_30(advisor); - // Create an input resource to convert org.hl7.fhir.dstu2.model.Observation input = new org.hl7.fhir.dstu2.model.Observation(); input.setEncounter(new org.hl7.fhir.dstu2.model.Reference("Encounter/123")); // Convert the resource - org.hl7.fhir.dstu3.model.Observation output = converter.convertObservation(input); + org.hl7.fhir.dstu3.model.Observation output = Observation10_30.convertObservation(input); String context = output.getContext().getReference(); //END SNIPPET: 1020 } @@ -31,7 +27,7 @@ public class ConverterExamples { input.setTitle("My title"); // Convert the resource - org.hl7.fhir.dstu3.model.Questionnaire output = VersionConvertor_14_30.convertQuestionnaire(input); + org.hl7.fhir.dstu3.model.Questionnaire output = Questionnaire14_30.convertQuestionnaire(input); String context = output.getTitle(); //END SNIPPET: 1420 } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/VersionEnum.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/VersionEnum.java index acc92dcb2a6..99d8ccd7939 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/VersionEnum.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/VersionEnum.java @@ -58,7 +58,8 @@ public enum VersionEnum { V4_0_0, V4_0_3, V4_1_0, - V4_2_0; + V4_2_0, + V4_3_0; public static VersionEnum latestVersion() { VersionEnum[] values = VersionEnum.values(); diff --git a/hapi-fhir-cli/hapi-fhir-cli-api/src/main/java/ca/uhn/fhir/cli/ExportConceptMapToCsvCommand.java b/hapi-fhir-cli/hapi-fhir-cli-api/src/main/java/ca/uhn/fhir/cli/ExportConceptMapToCsvCommand.java index 2a92f8df72a..1fc92fc6595 100644 --- a/hapi-fhir-cli/hapi-fhir-cli-api/src/main/java/ca/uhn/fhir/cli/ExportConceptMapToCsvCommand.java +++ b/hapi-fhir-cli/hapi-fhir-cli-api/src/main/java/ca/uhn/fhir/cli/ExportConceptMapToCsvCommand.java @@ -26,7 +26,6 @@ import org.apache.commons.cli.Options; import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVPrinter; import org.apache.commons.csv.QuoteMode; -import org.hl7.fhir.convertors.VersionConvertor_30_40; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.ConceptMap; @@ -43,6 +42,7 @@ import java.util.List; import java.util.concurrent.ExecutionException; import static org.apache.commons.lang3.StringUtils.defaultString; +import static org.hl7.fhir.convertors.conv30_40.ConceptMap30_40.convertConceptMap; public class ExportConceptMapToCsvCommand extends AbstractImportExportCsvConceptMapCommand { // TODO: Don't use qualified names for loggers in HAPI CLI. @@ -114,7 +114,7 @@ public class ExportConceptMapToCsvCommand extends AbstractImportExportCsvConcept private void convertConceptMapToCsv(org.hl7.fhir.dstu3.model.ConceptMap theConceptMap) throws ExecutionException { try { - convertConceptMapToCsv(VersionConvertor_30_40.convertConceptMap(theConceptMap)); + convertConceptMapToCsv(convertConceptMap(theConceptMap)); } catch (FHIRException fe) { throw new ExecutionException(fe); } diff --git a/hapi-fhir-cli/hapi-fhir-cli-api/src/main/java/ca/uhn/fhir/cli/ImportCsvToConceptMapCommand.java b/hapi-fhir-cli/hapi-fhir-cli-api/src/main/java/ca/uhn/fhir/cli/ImportCsvToConceptMapCommand.java index d44570b5d91..a795af5510a 100644 --- a/hapi-fhir-cli/hapi-fhir-cli-api/src/main/java/ca/uhn/fhir/cli/ImportCsvToConceptMapCommand.java +++ b/hapi-fhir-cli/hapi-fhir-cli-api/src/main/java/ca/uhn/fhir/cli/ImportCsvToConceptMapCommand.java @@ -28,7 +28,6 @@ import org.apache.commons.cli.Options; import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVParser; import org.apache.commons.csv.CSVRecord; -import org.hl7.fhir.convertors.VersionConvertor_30_40; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.r4.model.ConceptMap; import org.hl7.fhir.r4.model.ConceptMap.ConceptMapGroupComponent; @@ -45,7 +44,10 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutionException; -import static org.apache.commons.lang3.StringUtils.*; +import static org.apache.commons.lang3.StringUtils.defaultString; +import static org.apache.commons.lang3.StringUtils.isBlank; +import static org.apache.commons.lang3.StringUtils.isNotBlank; +import static org.hl7.fhir.convertors.conv30_40.ConceptMap30_40.convertConceptMap; public class ImportCsvToConceptMapCommand extends AbstractImportExportCsvConceptMapCommand { // TODO: Don't use qualified names for loggers in HAPI CLI. @@ -154,7 +156,7 @@ public class ImportCsvToConceptMapCommand extends AbstractImportExportCsvConcept private org.hl7.fhir.dstu3.model.ConceptMap convertCsvToConceptMapDstu3() throws ExecutionException { try { - return VersionConvertor_30_40.convertConceptMap(convertCsvToConceptMapR4()); + return convertConceptMap(convertCsvToConceptMapR4()); } catch (FHIRException fe) { throw new ExecutionException(fe); } @@ -174,7 +176,7 @@ public class ImportCsvToConceptMapCommand extends AbstractImportExportCsvConcept .withFirstRecordAsHeader() .withIgnoreHeaderCase() .withIgnoreEmptyLines() - .withTrim()); + .withTrim()) ) { retVal.setUrl(conceptMapUrl); diff --git a/hapi-fhir-converter/src/main/java/ca/uhn/hapi/converters/server/VersionedApiConverterInterceptor.java b/hapi-fhir-converter/src/main/java/ca/uhn/hapi/converters/server/VersionedApiConverterInterceptor.java index 28df8b376a1..7e2bb24d80c 100644 --- a/hapi-fhir-converter/src/main/java/ca/uhn/hapi/converters/server/VersionedApiConverterInterceptor.java +++ b/hapi-fhir-converter/src/main/java/ca/uhn/hapi/converters/server/VersionedApiConverterInterceptor.java @@ -31,7 +31,11 @@ import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.interceptor.InterceptorAdapter; import org.hl7.fhir.converter.NullVersionConverterAdvisor30; import org.hl7.fhir.converter.NullVersionConverterAdvisor40; -import org.hl7.fhir.convertors.*; +import org.hl7.fhir.convertors.VersionConvertorAdvisor30; +import org.hl7.fhir.convertors.VersionConvertorAdvisor40; +import org.hl7.fhir.convertors.VersionConvertor_10_30; +import org.hl7.fhir.convertors.VersionConvertor_10_40; +import org.hl7.fhir.convertors.VersionConvertor_30_40; import org.hl7.fhir.dstu3.model.Resource; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.instance.model.api.IBaseResource; @@ -40,7 +44,9 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.StringTokenizer; -import static org.apache.commons.lang3.StringUtils.*; +import static org.apache.commons.lang3.StringUtils.defaultString; +import static org.apache.commons.lang3.StringUtils.isBlank; +import static org.apache.commons.lang3.StringUtils.isNotBlank; /** * This is an experimental interceptor! Use with caution as @@ -54,16 +60,12 @@ import static org.apache.commons.lang3.StringUtils.*; public class VersionedApiConverterInterceptor extends InterceptorAdapter { private final FhirContext myCtxDstu2; private final FhirContext myCtxDstu2Hl7Org; - private VersionConvertor_30_40 myVersionConvertor_30_40; - private VersionConvertor_10_40 myVersionConvertor_10_40; - private VersionConvertor_10_30 myVersionConvertor_10_30; + private final NullVersionConverterAdvisor40 advisor40; + private final NullVersionConverterAdvisor30 advisor30; public VersionedApiConverterInterceptor() { - myVersionConvertor_30_40 = new VersionConvertor_30_40(); - VersionConvertorAdvisor40 advisor40 = new NullVersionConverterAdvisor40(); - myVersionConvertor_10_40 = new VersionConvertor_10_40(advisor40); - VersionConvertorAdvisor30 advisor30 = new NullVersionConverterAdvisor30(); - myVersionConvertor_10_30 = new VersionConvertor_10_30(advisor30); + advisor40 = new NullVersionConverterAdvisor40(); + advisor30 = new NullVersionConverterAdvisor30(); myCtxDstu2 = FhirContext.forDstu2(); myCtxDstu2Hl7Org = FhirContext.forDstu2Hl7Org(); @@ -104,17 +106,17 @@ public class VersionedApiConverterInterceptor extends InterceptorAdapter { IBaseResource converted = null; try { if (wantVersion == FhirVersionEnum.R4 && haveVersion == FhirVersionEnum.DSTU3) { - converted = myVersionConvertor_30_40.convertResource(toDstu3(responseResource), true); + converted = VersionConvertor_30_40.convertResource(toDstu3(responseResource), true); } else if (wantVersion == FhirVersionEnum.DSTU3 && haveVersion == FhirVersionEnum.R4) { - converted = myVersionConvertor_30_40.convertResource(toR4(responseResource), true); + converted = VersionConvertor_30_40.convertResource(toR4(responseResource), true); } else if (wantVersion == FhirVersionEnum.DSTU2 && haveVersion == FhirVersionEnum.R4) { - converted = myVersionConvertor_10_40.convertResource(toR4(responseResource)); + converted = VersionConvertor_10_40.convertResource(toR4(responseResource), advisor40); } else if (wantVersion == FhirVersionEnum.R4 && haveVersion == FhirVersionEnum.DSTU2) { - converted = myVersionConvertor_10_40.convertResource(toDstu2(responseResource)); + converted = VersionConvertor_10_40.convertResource(toDstu2(responseResource), advisor40); } else if (wantVersion == FhirVersionEnum.DSTU2 && haveVersion == FhirVersionEnum.DSTU3) { - converted = myVersionConvertor_10_30.convertResource(toDstu3(responseResource)); + converted = VersionConvertor_10_30.convertResource(toDstu3(responseResource), advisor30); } else if (wantVersion == FhirVersionEnum.DSTU3 && haveVersion == FhirVersionEnum.DSTU2) { - converted = myVersionConvertor_10_30.convertResource(toDstu2(responseResource)); + converted = VersionConvertor_10_30.convertResource(toDstu2(responseResource), advisor30); } } catch (FHIRException e) { throw new InternalErrorException(e); diff --git a/hapi-fhir-converter/src/main/java/org/hl7/fhir/converter/NullVersionConverterAdvisor50.java b/hapi-fhir-converter/src/main/java/org/hl7/fhir/converter/NullVersionConverterAdvisor50.java index 8b00abdffad..33d703f7a88 100644 --- a/hapi-fhir-converter/src/main/java/org/hl7/fhir/converter/NullVersionConverterAdvisor50.java +++ b/hapi-fhir-converter/src/main/java/org/hl7/fhir/converter/NullVersionConverterAdvisor50.java @@ -27,8 +27,12 @@ import org.hl7.fhir.r5.model.Bundle; import org.hl7.fhir.r5.model.CodeSystem; import org.hl7.fhir.r5.model.ValueSet; +import java.util.IdentityHashMap; + public class NullVersionConverterAdvisor50 implements VersionConvertorAdvisor50 { + private IdentityHashMap myCodeSystems = new IdentityHashMap<>(); + @Override public boolean ignoreEntry(Bundle.BundleEntryComponent src) { return false; @@ -56,11 +60,11 @@ public class NullVersionConverterAdvisor50 implements VersionConvertorAdvisor50 @Override public void handleCodeSystem(CodeSystem tgtcs, ValueSet source) throws FHIRException { - + myCodeSystems.put(source, tgtcs); } @Override public CodeSystem getCodeSystem(ValueSet src) throws FHIRException { - return null; + return myCodeSystems.get(src); } } diff --git a/hapi-fhir-converter/src/test/java/org/hl7/fhir/converter/VersionConvertor_10_30Test.java b/hapi-fhir-converter/src/test/java/org/hl7/fhir/converter/VersionConvertor_10_30Test.java index be77cdb8515..a63a0d86344 100644 --- a/hapi-fhir-converter/src/test/java/org/hl7/fhir/converter/VersionConvertor_10_30Test.java +++ b/hapi-fhir-converter/src/test/java/org/hl7/fhir/converter/VersionConvertor_10_30Test.java @@ -16,13 +16,10 @@ public class VersionConvertor_10_30Test { @Test public void testConvert() throws FHIRException { - NullVersionConverterAdvisor30 advisor = new NullVersionConverterAdvisor30(); - VersionConvertor_10_30 converter = new VersionConvertor_10_30(advisor); - org.hl7.fhir.dstu2.model.Observation input = new org.hl7.fhir.dstu2.model.Observation(); input.setEncounter(new org.hl7.fhir.dstu2.model.Reference("Encounter/123")); - org.hl7.fhir.dstu3.model.Observation output = converter.convertObservation(input); + org.hl7.fhir.dstu3.model.Observation output = (Observation) VersionConvertor_10_30.convertResource(input); String context = output.getContext().getReference(); assertEquals("Encounter/123", context); @@ -31,9 +28,6 @@ public class VersionConvertor_10_30Test { @Test public void testConvertSpecimen() throws FHIRException { - NullVersionConverterAdvisor30 advisor = new NullVersionConverterAdvisor30(); - VersionConvertor_10_30 converter = new VersionConvertor_10_30(advisor); - Specimen spec = new Specimen(); CodeableConcept cc = new CodeableConcept(); Coding coding = new Coding(); @@ -58,7 +52,7 @@ public class VersionConvertor_10_30Test { Specimen.SpecimenContainerComponent specimenContainerComponent = new Specimen.SpecimenContainerComponent(); specimenContainerComponent.getExtension().add(new Extension().setUrl("some_url").setValue(new StringType("some_value"))); spec.setContainer(Collections.singletonList(specimenContainerComponent)); - Resource resource = converter.convertResource(spec); + Resource resource = VersionConvertor_10_30.convertResource(spec); } diff --git a/hapi-fhir-converter/src/test/java/org/hl7/fhir/converter/VersionConvertor_14_30Test.java b/hapi-fhir-converter/src/test/java/org/hl7/fhir/converter/VersionConvertor_14_30Test.java index 14fa9db116a..8914d474e01 100644 --- a/hapi-fhir-converter/src/test/java/org/hl7/fhir/converter/VersionConvertor_14_30Test.java +++ b/hapi-fhir-converter/src/test/java/org/hl7/fhir/converter/VersionConvertor_14_30Test.java @@ -3,6 +3,7 @@ package org.hl7.fhir.converter; import static org.junit.Assert.assertEquals; import org.hl7.fhir.convertors.VersionConvertor_14_30; +import org.hl7.fhir.dstu3.model.Questionnaire; import org.hl7.fhir.exceptions.FHIRException; import org.junit.Test; @@ -14,7 +15,7 @@ public class VersionConvertor_14_30Test { org.hl7.fhir.dstu2016may.model.Questionnaire input = new org.hl7.fhir.dstu2016may.model.Questionnaire(); input.setTitle("My title"); - org.hl7.fhir.dstu3.model.Questionnaire output = VersionConvertor_14_30.convertQuestionnaire(input); + org.hl7.fhir.dstu3.model.Questionnaire output = (Questionnaire) VersionConvertor_14_30.convertResource(input); String context = output.getTitle(); assertEquals("My title", context); diff --git a/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/ConverterExamples.java b/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/ConverterExamples.java index 5da62480bdc..0da2042b969 100644 --- a/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/ConverterExamples.java +++ b/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/ConverterExamples.java @@ -20,9 +20,8 @@ package ca.uhn.hapi.fhir.docs; * #L% */ -import org.hl7.fhir.converter.NullVersionConverterAdvisor30; -import org.hl7.fhir.convertors.VersionConvertor_10_30; -import org.hl7.fhir.convertors.VersionConvertor_14_30; +import org.hl7.fhir.convertors.conv10_30.Observation10_30; +import org.hl7.fhir.convertors.conv14_30.Questionnaire14_30; import org.hl7.fhir.exceptions.FHIRException; public class ConverterExamples { @@ -30,16 +29,12 @@ public class ConverterExamples { @SuppressWarnings("unused") public void c1020() throws FHIRException { //START SNIPPET: 1020 - // Create a converter - NullVersionConverterAdvisor30 advisor = new NullVersionConverterAdvisor30(); - VersionConvertor_10_30 converter = new VersionConvertor_10_30(advisor); - // Create an input resource to convert org.hl7.fhir.dstu2.model.Observation input = new org.hl7.fhir.dstu2.model.Observation(); input.setEncounter(new org.hl7.fhir.dstu2.model.Reference("Encounter/123")); // Convert the resource - org.hl7.fhir.dstu3.model.Observation output = converter.convertObservation(input); + org.hl7.fhir.dstu3.model.Observation output = Observation10_30.convertObservation(input); String context = output.getContext().getReference(); //END SNIPPET: 1020 } @@ -52,7 +47,7 @@ public class ConverterExamples { input.setTitle("My title"); // Convert the resource - org.hl7.fhir.dstu3.model.Questionnaire output = VersionConvertor_14_30.convertQuestionnaire(input); + org.hl7.fhir.dstu3.model.Questionnaire output = Questionnaire14_30.convertQuestionnaire(input); String context = output.getTitle(); //END SNIPPET: 1420 } diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/4_3_0/1715-update-converters.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/4_3_0/1715-update-converters.yaml new file mode 100644 index 00000000000..874c6fe3520 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/4_3_0/1715-update-converters.yaml @@ -0,0 +1,6 @@ +--- +type: change +issue: 1715 +title: The version converters for all versions except R4/R5 have been reworked to be split into individual + classes per resource type (the R4/R5 converters were already organized this way). Thanks to Mark Iantorno + for a huge effort to write a Java source parser/serializer to acomplish this task. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoCodeSystemDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoCodeSystemDstu3.java index 1377a5287cd..0947af92164 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoCodeSystemDstu3.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoCodeSystemDstu3.java @@ -24,10 +24,10 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.support.IContextValidationSupport; import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao; import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem; -import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource; -import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId; import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemDao; import ca.uhn.fhir.jpa.entity.TermCodeSystem; +import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource; +import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId; import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc; @@ -35,7 +35,6 @@ import ca.uhn.fhir.jpa.util.LogicUtil; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.param.TokenParam; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; -import org.hl7.fhir.convertors.VersionConvertor_30_40; import org.hl7.fhir.dstu3.hapi.validation.ValidationSupportChain; import org.hl7.fhir.dstu3.model.CodeSystem; import org.hl7.fhir.dstu3.model.CodeableConcept; @@ -53,6 +52,7 @@ import java.util.List; import java.util.Set; import static org.apache.commons.lang3.StringUtils.isNotBlank; +import static org.hl7.fhir.convertors.conv30_40.CodeSystem30_40.convertCodeSystem; @Transactional public class FhirResourceDaoCodeSystemDstu3 extends BaseHapiFhirResourceDao implements IFhirResourceDaoCodeSystem { @@ -147,7 +147,7 @@ public class FhirResourceDaoCodeSystemDstu3 extends BaseHapiFhirResourceDao implements IFhirResourceDaoConceptMap { @Autowired private ITermReadSvc myHapiTerminologySvc; @@ -166,7 +171,7 @@ public class FhirResourceDaoConceptMapDstu3 extends BaseHapiFhirResourceDao implements IFhirResourceDaoValueSet { private static final Logger ourLog = LoggerFactory.getLogger(FhirResourceDaoValueSetDstu3.class); @@ -420,7 +423,7 @@ public class FhirResourceDaoValueSetDstu3 extends BaseHapiFhirResourceDao if (myDaoConfig.isPreExpandValueSets() && !retVal.isUnchangedInCurrentOperation()) { if (retVal.getDeleted() == null) { ValueSet valueSet = (ValueSet) theResource; - myHapiTerminologySvc.storeTermValueSet(retVal, org.hl7.fhir.convertors.conv40_50.ValueSet.convertValueSet(valueSet)); + myHapiTerminologySvc.storeTermValueSet(retVal, org.hl7.fhir.convertors.conv40_50.ValueSet40_50.convertValueSet(valueSet)); } else { myHapiTerminologySvc.deleteValueSetAndChildren(retVal); } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/TerminologyUploaderProvider.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/TerminologyUploaderProvider.java index d6ee3364a47..90a27e56c48 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/TerminologyUploaderProvider.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/TerminologyUploaderProvider.java @@ -39,7 +39,6 @@ import ca.uhn.fhir.util.ValidateUtil; import com.google.common.base.Charsets; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; -import org.hl7.fhir.convertors.VersionConvertor_30_40; import org.hl7.fhir.instance.model.api.IBaseParameters; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.ICompositeType; @@ -61,6 +60,7 @@ import java.util.Map; import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.trim; +import static org.hl7.fhir.convertors.conv30_40.CodeSystem30_40.convertCodeSystem; public class TerminologyUploaderProvider extends BaseJpaProvider { @@ -272,10 +272,10 @@ public class TerminologyUploaderProvider extends BaseJpaProvider { CodeSystem nextCodeSystem; switch (getContext().getVersion().getVersion()) { case DSTU3: - nextCodeSystem = VersionConvertor_30_40.convertCodeSystem((org.hl7.fhir.dstu3.model.CodeSystem) theCodeSystem); + nextCodeSystem = convertCodeSystem((org.hl7.fhir.dstu3.model.CodeSystem) theCodeSystem); break; case R5: - nextCodeSystem = org.hl7.fhir.convertors.conv40_50.CodeSystem.convertCodeSystem((org.hl7.fhir.r5.model.CodeSystem) theCodeSystem); + nextCodeSystem = org.hl7.fhir.convertors.conv40_50.CodeSystem40_50.convertCodeSystem((org.hl7.fhir.r5.model.CodeSystem) theCodeSystem); break; default: nextCodeSystem = (CodeSystem) theCodeSystem; diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/BaseJpaResourceProviderConceptMapDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/BaseJpaResourceProviderConceptMapDstu3.java index 7bcfee951a4..0f42082bbef 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/BaseJpaResourceProviderConceptMapDstu3.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/BaseJpaResourceProviderConceptMapDstu3.java @@ -21,9 +21,9 @@ package ca.uhn.fhir.jpa.provider.dstu3; */ import ca.uhn.fhir.jpa.dao.IFhirResourceDaoConceptMap; +import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.jpa.term.TranslationRequest; import ca.uhn.fhir.jpa.term.TranslationResult; -import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.rest.annotation.IdParam; import ca.uhn.fhir.rest.annotation.Operation; import ca.uhn.fhir.rest.annotation.OperationParam; @@ -31,11 +31,21 @@ import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import org.hl7.fhir.convertors.VersionConvertor_30_40; -import org.hl7.fhir.dstu3.model.*; +import org.hl7.fhir.dstu3.model.BooleanType; +import org.hl7.fhir.dstu3.model.CodeType; +import org.hl7.fhir.dstu3.model.CodeableConcept; +import org.hl7.fhir.dstu3.model.Coding; +import org.hl7.fhir.dstu3.model.ConceptMap; +import org.hl7.fhir.dstu3.model.IdType; +import org.hl7.fhir.dstu3.model.Parameters; +import org.hl7.fhir.dstu3.model.StringType; +import org.hl7.fhir.dstu3.model.UriType; import org.hl7.fhir.exceptions.FHIRException; import javax.servlet.http.HttpServletRequest; +import static org.hl7.fhir.convertors.conv30_40.Parameters30_40.convertParameters; + public class BaseJpaResourceProviderConceptMapDstu3 extends JpaResourceProviderDstu3 { @Operation(name = JpaConstants.OPERATION_TRANSLATE, idempotent = true, returnParameters = { @OperationParam(name = "result", type = BooleanType.class, min = 1, max = 1), @@ -129,7 +139,7 @@ public class BaseJpaResourceProviderConceptMapDstu3 extends JpaResourceProviderD TranslationResult result = dao.translate(translationRequest, theRequestDetails); // Convert from R4 to DSTU3 - return VersionConvertor_30_40.convertParameters(result.toParameters()); + return convertParameters(result.toParameters()); } catch (FHIRException fe) { throw new InternalErrorException(fe); } finally { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/JpaResourceProviderDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/JpaResourceProviderDstu3.java index e6376d2ddf1..42aec253031 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/JpaResourceProviderDstu3.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/JpaResourceProviderDstu3.java @@ -21,17 +21,28 @@ package ca.uhn.fhir.jpa.provider.dstu3; */ import ca.uhn.fhir.jpa.dao.IFhirResourceDao; -import ca.uhn.fhir.jpa.provider.BaseJpaResourceProvider; import ca.uhn.fhir.jpa.model.util.JpaConstants; -import ca.uhn.fhir.rest.annotation.*; +import ca.uhn.fhir.jpa.provider.BaseJpaResourceProvider; +import ca.uhn.fhir.rest.annotation.ConditionalUrlParam; +import ca.uhn.fhir.rest.annotation.Create; +import ca.uhn.fhir.rest.annotation.Delete; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.Operation; +import ca.uhn.fhir.rest.annotation.OperationParam; +import ca.uhn.fhir.rest.annotation.ResourceParam; +import ca.uhn.fhir.rest.annotation.Update; +import ca.uhn.fhir.rest.annotation.Validate; import ca.uhn.fhir.rest.api.EncodingEnum; import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.ValidationModeEnum; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; -import org.hl7.fhir.convertors.VersionConvertor_30_40; -import org.hl7.fhir.dstu3.model.*; +import org.hl7.fhir.dstu3.model.BooleanType; +import org.hl7.fhir.dstu3.model.IdType; +import org.hl7.fhir.dstu3.model.IntegerType; +import org.hl7.fhir.dstu3.model.Meta; +import org.hl7.fhir.dstu3.model.Parameters; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.instance.model.api.IAnyResource; import org.hl7.fhir.instance.model.api.IIdType; @@ -41,6 +52,7 @@ import javax.servlet.http.HttpServletRequest; import static ca.uhn.fhir.jpa.model.util.JpaConstants.OPERATION_META; import static ca.uhn.fhir.jpa.model.util.JpaConstants.OPERATION_META_ADD; import static ca.uhn.fhir.jpa.model.util.JpaConstants.OPERATION_META_DELETE; +import static org.hl7.fhir.convertors.conv30_40.Parameters30_40.convertParameters; public class JpaResourceProviderDstu3 extends BaseJpaResourceProvider { @@ -91,7 +103,7 @@ public class JpaResourceProviderDstu3 extends BaseJpaRes RequestDetails theRequest) { org.hl7.fhir.r4.model.Parameters retVal = super.doExpunge(theIdParam, theLimit, theExpungeDeletedResources, theExpungeOldVersions, null, theRequest); try { - return VersionConvertor_30_40.convertParameters(retVal); + return convertParameters(retVal); } catch (FHIRException e) { throw new InternalErrorException(e); } @@ -107,7 +119,7 @@ public class JpaResourceProviderDstu3 extends BaseJpaRes RequestDetails theRequest) { org.hl7.fhir.r4.model.Parameters retVal = super.doExpunge(null, theLimit, theExpungeDeletedResources, theExpungeOldVersions, null, theRequest); try { - return VersionConvertor_30_40.convertParameters(retVal); + return convertParameters(retVal); } catch (FHIRException e) { throw new InternalErrorException(e); } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/JpaSystemProviderDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/JpaSystemProviderDstu3.java index f345c6f7361..c1f1970a0c1 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/JpaSystemProviderDstu3.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/JpaSystemProviderDstu3.java @@ -3,17 +3,26 @@ package ca.uhn.fhir.jpa.provider.dstu3; import ca.uhn.fhir.jpa.dao.FulltextSearchSvcImpl.Suggestion; import ca.uhn.fhir.jpa.dao.IFhirSystemDao; import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc; -import ca.uhn.fhir.jpa.provider.BaseJpaSystemProviderDstu2Plus; import ca.uhn.fhir.jpa.model.util.JpaConstants; +import ca.uhn.fhir.jpa.provider.BaseJpaSystemProviderDstu2Plus; import ca.uhn.fhir.model.api.annotation.Description; -import ca.uhn.fhir.rest.annotation.*; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.Operation; +import ca.uhn.fhir.rest.annotation.OperationParam; +import ca.uhn.fhir.rest.annotation.Transaction; +import ca.uhn.fhir.rest.annotation.TransactionParam; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; -import org.hl7.fhir.convertors.VersionConvertor_30_40; -import org.hl7.fhir.dstu3.model.*; +import org.hl7.fhir.dstu3.model.BooleanType; +import org.hl7.fhir.dstu3.model.Bundle; +import org.hl7.fhir.dstu3.model.DecimalType; +import org.hl7.fhir.dstu3.model.IntegerType; +import org.hl7.fhir.dstu3.model.Meta; +import org.hl7.fhir.dstu3.model.Parameters; import org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent; +import org.hl7.fhir.dstu3.model.StringType; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.instance.model.api.IBaseBundle; import org.hl7.fhir.instance.model.api.IIdType; @@ -29,6 +38,7 @@ import java.util.TreeMap; import static org.apache.commons.lang3.ObjectUtils.defaultIfNull; import static org.apache.commons.lang3.StringUtils.isBlank; +import static org.hl7.fhir.convertors.conv30_40.Parameters30_40.convertParameters; /* * #%L @@ -72,7 +82,7 @@ public class JpaSystemProviderDstu3 extends BaseJpaSystemProviderDstu2Plus dao = (IFhirResourceDaoConceptMap) getDao(); TranslationResult result = dao.translate(translationRequest, theRequestDetails); org.hl7.fhir.r4.model.Parameters parameters = result.toParameters(); - return org.hl7.fhir.convertors.conv40_50.Parameters.convertParameters(parameters); + return org.hl7.fhir.convertors.conv40_50.Parameters40_50.convertParameters(parameters); } finally { endRequest(theServletRequest); } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r5/JpaResourceProviderR5.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r5/JpaResourceProviderR5.java index e3e4c6b54de..ef86e4f478b 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r5/JpaResourceProviderR5.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r5/JpaResourceProviderR5.java @@ -86,7 +86,7 @@ public class JpaResourceProviderR5 extends BaseJpaResour RequestDetails theRequest) { org.hl7.fhir.r4.model.Parameters parameters = super.doExpunge(theIdParam, theLimit, theExpungeDeletedResources, theExpungeOldVersions, null, theRequest); - return org.hl7.fhir.convertors.conv40_50.Parameters.convertParameters(parameters); + return org.hl7.fhir.convertors.conv40_50.Parameters40_50.convertParameters(parameters); } @@ -99,7 +99,7 @@ public class JpaResourceProviderR5 extends BaseJpaResour @OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_PREVIOUS_VERSIONS) BooleanType theExpungeOldVersions, RequestDetails theRequest) { org.hl7.fhir.r4.model.Parameters parameters = super.doExpunge(null, theLimit, theExpungeDeletedResources, theExpungeOldVersions, null, theRequest); - return org.hl7.fhir.convertors.conv40_50.Parameters.convertParameters(parameters); + return org.hl7.fhir.convertors.conv40_50.Parameters40_50.convertParameters(parameters); } @Operation(name = OPERATION_META, idempotent = true, returnParameters = { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r5/JpaSystemProviderR5.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r5/JpaSystemProviderR5.java index 7bacb42b6ba..4a99a931bbe 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r5/JpaSystemProviderR5.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r5/JpaSystemProviderR5.java @@ -68,7 +68,7 @@ public class JpaSystemProviderR5 extends BaseJpaSystemProviderDstu2Plus T fetchResource(Class theClass, String theUri) { + Validate.notBlank(theUri, "theUri must not be null or blank"); if (myValidationSupport == null) { return null; } else { - @SuppressWarnings("unchecked") - T retVal = (T) myFetchedResourceCache.get(theUri, t->{ - return myValidationSupport.fetchResource(myCtx, theClass, theUri); - }); - return retVal; + try { + //noinspection unchecked + return (T) myFetchedResourceCache.get(theUri, t -> { + T resource = myValidationSupport.fetchResource(myCtx, theClass, theUri); + if (resource == null) { + throw new IllegalArgumentException(); + } + return resource; + }); + } catch (IllegalArgumentException e) { + return null; + } } } diff --git a/hapi-fhir-structures-r5/src/main/java/org/hl7/fhir/r5/hapi/ctx/HapiWorkerContext.java b/hapi-fhir-structures-r5/src/main/java/org/hl7/fhir/r5/hapi/ctx/HapiWorkerContext.java index c48a81f8f5e..c88ada2d294 100644 --- a/hapi-fhir-structures-r5/src/main/java/org/hl7/fhir/r5/hapi/ctx/HapiWorkerContext.java +++ b/hapi-fhir-structures-r5/src/main/java/org/hl7/fhir/r5/hapi/ctx/HapiWorkerContext.java @@ -343,6 +343,11 @@ public final class HapiWorkerContext implements IWorkerContext, ValueSetExpander return fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + typeName); } + @Override + public StructureDefinition fetchRawProfile(String url) { + throw new UnsupportedOperationException(); + } + @Override public List getTypeNames() { throw new UnsupportedOperationException(); diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/ValidatorWrapper.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/ValidatorWrapper.java index d1c28f2b274..37323be9e1c 100644 --- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/ValidatorWrapper.java +++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/ValidatorWrapper.java @@ -4,20 +4,24 @@ import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.rest.api.EncodingEnum; import ca.uhn.fhir.util.XmlUtil; import ca.uhn.fhir.validation.IValidationContext; -import com.google.gson.*; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import org.apache.commons.codec.Charsets; import org.apache.commons.io.input.ReaderInputStream; +import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.elementmodel.Manager; +import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.utils.FHIRPathEngine; import org.hl7.fhir.r5.utils.IResourceValidator; -import org.hl7.fhir.r5.utils.ValidationProfileSet; import org.hl7.fhir.r5.validation.InstanceValidator; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; -import org.w3c.dom.Element; import org.w3c.dom.NodeList; import java.io.InputStream; @@ -33,7 +37,9 @@ public class ValidatorWrapper { private boolean myAnyExtensionsAllowed; private boolean myErrorForUnknownProfiles; private boolean myNoTerminologyChecks; + private boolean myAssumeValidRestReferences; private Collection myExtensionDomains; + private IResourceValidator.IValidatorResourceFetcher myValidatorResourceFetcher; /** * Constructor @@ -42,6 +48,15 @@ public class ValidatorWrapper { super(); } + public boolean isAssumeValidRestReferences() { + return myAssumeValidRestReferences; + } + + public ValidatorWrapper setAssumeValidRestReferences(boolean assumeValidRestReferences) { + this.myAssumeValidRestReferences = assumeValidRestReferences; + return this; + } + public ValidatorWrapper setBestPracticeWarningLevel(IResourceValidator.BestPracticeWarningLevel theBestPracticeWarningLevel) { myBestPracticeWarningLevel = theBestPracticeWarningLevel; return this; @@ -67,6 +82,12 @@ public class ValidatorWrapper { return this; } + + public ValidatorWrapper setValidatorResourceFetcher(IResourceValidator.IValidatorResourceFetcher validatorResourceFetcher) { + this.myValidatorResourceFetcher = validatorResourceFetcher; + return this; + } + public List validate(IWorkerContext theWorkerContext, IValidationContext theValidationContext) { InstanceValidator v; FHIRPathEngine.IEvaluationContext evaluationCtx = new org.hl7.fhir.r5.hapi.validation.FhirInstanceValidator.NullEvaluationContext(); @@ -76,19 +97,21 @@ public class ValidatorWrapper { throw new ConfigurationException(e); } + v.setAssumeValidRestReferences(isAssumeValidRestReferences()); v.setBestPracticeWarningLevel(myBestPracticeWarningLevel); v.setAnyExtensionsAllowed(myAnyExtensionsAllowed); v.setResourceIdRule(IResourceValidator.IdStatus.OPTIONAL); v.setNoTerminologyChecks(myNoTerminologyChecks); v.setErrorForUnknownProfiles(myErrorForUnknownProfiles); v.getExtensionDomains().addAll(myExtensionDomains); + v.setFetcher(myValidatorResourceFetcher); v.setAllowXsiLocation(true); List messages = new ArrayList<>(); - ValidationProfileSet profileSet = new ValidationProfileSet(); + List profileUrls = new ArrayList<>(); for (String next : theValidationContext.getOptions().getProfiles()) { - profileSet.getCanonical().add(new ValidationProfileSet.ProfileRegistration(next, true)); + fetchAndAddProfile(theWorkerContext, profileUrls, next); } String input = theValidationContext.getResourceAsString(); @@ -109,14 +132,14 @@ public class ValidatorWrapper { // Determine if meta/profiles are present... ArrayList profiles = determineIfProfilesSpecified(document); for (String nextProfile : profiles) { - profileSet.getCanonical().add(new ValidationProfileSet.ProfileRegistration(nextProfile, true)); + fetchAndAddProfile(theWorkerContext, profileUrls, nextProfile); } String resourceAsString = theValidationContext.getResourceAsString(); InputStream inputStream = new ReaderInputStream(new StringReader(resourceAsString), Charsets.UTF_8); Manager.FhirFormat format = Manager.FhirFormat.XML; - v.validate(null, messages, inputStream, format, profileSet); + v.validate(null, messages, inputStream, format, profileUrls); } else if (encoding == EncodingEnum.JSON) { @@ -129,7 +152,8 @@ public class ValidatorWrapper { if (profileElement != null && profileElement.isJsonArray()) { JsonArray profiles = profileElement.getAsJsonArray(); for (JsonElement element : profiles) { - profileSet.getCanonical().add(new ValidationProfileSet.ProfileRegistration(element.getAsString(), true)); + String nextProfile = element.getAsString(); + fetchAndAddProfile(theWorkerContext, profileUrls, nextProfile); } } } @@ -138,7 +162,7 @@ public class ValidatorWrapper { InputStream inputStream = new ReaderInputStream(new StringReader(resourceAsString), Charsets.UTF_8); Manager.FhirFormat format = Manager.FhirFormat.JSON; - v.validate(null, messages, inputStream, format, profileSet); + v.validate(null, messages, inputStream, format, profileUrls); } else { throw new IllegalArgumentException("Unknown encoding: " + encoding); @@ -157,17 +181,16 @@ public class ValidatorWrapper { return messages; } - - private String determineResourceName(Document theDocument) { - NodeList list = theDocument.getChildNodes(); - for (int i = 0; i < list.getLength(); i++) { - if (list.item(i) instanceof Element) { - return list.item(i).getLocalName(); - } + private void fetchAndAddProfile(IWorkerContext theWorkerContext, List theProfileStructureDefinitions, String theUrl) throws org.hl7.fhir.exceptions.FHIRException { + try { + StructureDefinition structureDefinition = theWorkerContext.fetchResourceWithException(StructureDefinition.class, theUrl); + theProfileStructureDefinitions.add(structureDefinition); + } catch (FHIRException e) { + ourLog.debug("Failed to load profile: {}", theUrl); } - return theDocument.getDocumentElement().getLocalName(); } + private ArrayList determineIfProfilesSpecified(Document theDocument) { ArrayList profileNames = new ArrayList<>(); NodeList list = theDocument.getChildNodes().item(0).getChildNodes(); diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/dstu2016may/hapi/validation/FhirInstanceValidator.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/dstu2016may/hapi/validation/FhirInstanceValidator.java index e583381a5ee..e4ab01d7f78 100644 --- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/dstu2016may/hapi/validation/FhirInstanceValidator.java +++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/dstu2016may/hapi/validation/FhirInstanceValidator.java @@ -1,14 +1,10 @@ package org.hl7.fhir.dstu2016may.hapi.validation; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.*; -import java.util.concurrent.TimeUnit; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - +import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.rest.api.Constants; +import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; +import ca.uhn.fhir.validation.IValidationContext; +import ca.uhn.fhir.validation.IValidatorModule; import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.LoadingCache; import org.apache.commons.lang3.Validate; @@ -18,28 +14,45 @@ import org.apache.commons.lang3.time.DateUtils; import org.fhir.ucum.UcumService; import org.hl7.fhir.common.hapi.validation.ValidatorWrapper; import org.hl7.fhir.convertors.VersionConvertor_14_50; +import org.hl7.fhir.convertors.conv14_50.CodeSystem14_50; +import org.hl7.fhir.convertors.conv14_50.StructureDefinition14_50; +import org.hl7.fhir.convertors.conv14_50.ValueSet14_50; +import org.hl7.fhir.dstu2016may.model.CodeSystem; +import org.hl7.fhir.dstu2016may.model.CodeableConcept; +import org.hl7.fhir.dstu2016may.model.Coding; +import org.hl7.fhir.dstu2016may.model.ImplementationGuide; +import org.hl7.fhir.dstu2016may.model.Questionnaire; +import org.hl7.fhir.dstu2016may.model.StructureDefinition; +import org.hl7.fhir.dstu2016may.model.ValueSet; import org.hl7.fhir.exceptions.DefinitionException; +import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.TerminologyServiceException; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.formats.IParser; import org.hl7.fhir.r5.formats.ParserType; import org.hl7.fhir.r5.model.CanonicalResource; +import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.utils.INarrativeGenerator; import org.hl7.fhir.r5.utils.IResourceValidator; -import org.hl7.fhir.r5.model.Resource; -import org.hl7.fhir.dstu2016may.model.*; -import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.utilities.TerminologyServiceOptions; import org.hl7.fhir.utilities.TranslationServices; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationOptions; -import org.w3c.dom.*; +import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.w3c.dom.NodeList; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; -import ca.uhn.fhir.validation.IValidationContext; -import ca.uhn.fhir.validation.IValidatorModule; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; public class FhirInstanceValidator extends BaseValidatorBridge implements IValidatorModule { @@ -382,7 +395,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid } public org.hl7.fhir.r5.model.StructureDefinition convert(StructureDefinition next) { - org.hl7.fhir.r5.model.StructureDefinition structureDefinition = VersionConvertor_14_50.convertStructureDefinition(next); + org.hl7.fhir.r5.model.StructureDefinition structureDefinition = StructureDefinition14_50.convertStructureDefinition(next); if (next.getDerivation() != org.hl7.fhir.dstu2016may.model.StructureDefinition.TypeDerivationRule.CONSTRAINT) { structureDefinition.setType(next.getName()); } @@ -408,7 +421,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent conceptDefinition = null; if (theResult.asConceptDefinition() != null) { try { - conceptDefinition = VersionConvertor_14_50.convertConceptDefinitionComponent(theResult.asConceptDefinition()); + conceptDefinition = CodeSystem14_50.convertConceptDefinitionComponent(theResult.asConceptDefinition()); } catch (FHIRException e) { throw new InternalErrorException(e); } @@ -428,7 +441,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid public org.hl7.fhir.r5.terminologies.ValueSetExpander.ValueSetExpansionOutcome expandVS(org.hl7.fhir.r5.model.ValueSet source, boolean cacheOk, boolean heiarchical) { ValueSet convertedSource; try { - convertedSource = VersionConvertor_14_50.convertValueSet(source); + convertedSource = ValueSet14_50.convertValueSet(source); } catch (FHIRException e) { throw new InternalErrorException(e); } @@ -437,7 +450,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid org.hl7.fhir.r5.model.ValueSet convertedResult = null; if (expanded.getValueset() != null) { try { - convertedResult = VersionConvertor_14_50.convertValueSet(expanded.getValueset()); + convertedResult = ValueSet14_50.convertValueSet(expanded.getValueset()); } catch (FHIRException e) { throw new InternalErrorException(e); } @@ -458,7 +471,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid ValueSet.ConceptSetComponent convertedInc = null; if (inc != null) { try { - convertedInc = VersionConvertor_14_50.convertConceptSetComponent(inc); + convertedInc = ValueSet14_50.convertConceptSetComponent(inc); } catch (FHIRException e) { throw new InternalErrorException(e); } @@ -468,7 +481,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionComponent valueSetExpansionComponent = null; if (expansion != null) { try { - valueSetExpansionComponent = VersionConvertor_14_50.convertValueSetExpansionComponent(expansion); + valueSetExpansionComponent = ValueSet14_50.convertValueSetExpansionComponent(expansion); } catch (FHIRException e) { throw new InternalErrorException(e); } @@ -492,7 +505,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid return null; } try { - return VersionConvertor_14_50.convertCodeSystem(fetched); + return CodeSystem14_50.convertCodeSystem(fetched); } catch (FHIRException e) { throw new InternalErrorException(e); } @@ -572,6 +585,11 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid return fetchResource(org.hl7.fhir.r5.model.StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + typeName); } + @Override + public org.hl7.fhir.r5.model.StructureDefinition fetchRawProfile(String url) { + return fetchResource(org.hl7.fhir.r5.model.StructureDefinition.class, url); + } + @Override public List getTypeNames() { @@ -665,7 +683,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid try { if (vs != null) { - convertedVs = VersionConvertor_14_50.convertValueSet(vs); + convertedVs = ValueSet14_50.convertValueSet(vs); } } catch (FHIRException e) { throw new InternalErrorException(e); @@ -680,7 +698,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid ValueSet convertedVs = null; try { if (vs != null) { - convertedVs = VersionConvertor_14_50.convertValueSet(vs); + convertedVs = ValueSet14_50.convertValueSet(vs); } } catch (FHIRException e) { throw new InternalErrorException(e); @@ -700,7 +718,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid convertedCode = VersionConvertor_14_50.convertCoding(code); } if (vs != null) { - convertedVs = VersionConvertor_14_50.convertValueSet(vs); + convertedVs = ValueSet14_50.convertValueSet(vs); } } catch (FHIRException e) { throw new InternalErrorException(e); @@ -720,7 +738,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid convertedCode = VersionConvertor_14_50.convertCodeableConcept(code); } if (vs != null) { - convertedVs = VersionConvertor_14_50.convertValueSet(vs); + convertedVs = ValueSet14_50.convertValueSet(vs); } } catch (FHIRException e) { throw new InternalErrorException(e); diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/dstu3/hapi/validation/FhirInstanceValidator.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/dstu3/hapi/validation/FhirInstanceValidator.java index ba3c7a8755f..609941ba6a9 100644 --- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/dstu3/hapi/validation/FhirInstanceValidator.java +++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/dstu3/hapi/validation/FhirInstanceValidator.java @@ -23,6 +23,7 @@ import org.hl7.fhir.dstu3.model.Coding; import org.hl7.fhir.dstu3.model.ImplementationGuide; import org.hl7.fhir.dstu3.model.Questionnaire; import org.hl7.fhir.dstu3.model.Resource; +import org.hl7.fhir.dstu3.model.SearchParameter; import org.hl7.fhir.dstu3.model.StructureDefinition; import org.hl7.fhir.dstu3.model.ValueSet; import org.hl7.fhir.exceptions.FHIRException; @@ -56,6 +57,13 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; +import static org.hl7.fhir.convertors.conv30_50.CodeSystem30_50.convertCodeSystem; +import static org.hl7.fhir.convertors.conv30_50.CodeSystem30_50.convertConceptDefinitionComponent; +import static org.hl7.fhir.convertors.conv30_50.StructureDefinition30_50.convertStructureDefinition; +import static org.hl7.fhir.convertors.conv30_50.ValueSet30_50.convertConceptSetComponent; +import static org.hl7.fhir.convertors.conv30_50.ValueSet30_50.convertValueSet; +import static org.hl7.fhir.convertors.conv30_50.ValueSet30_50.convertValueSetExpansionComponent; + @SuppressWarnings({"PackageAccessibility", "Duplicates"}) public class FhirInstanceValidator extends BaseValidatorBridge implements IInstanceValidatorModule { @@ -66,10 +74,12 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta private StructureDefinition myStructureDefintion; private IValidationSupport myValidationSupport; private boolean noTerminologyChecks = false; + private IResourceValidator.IValidatorResourceFetcher validatorResourceFetcher; private volatile WorkerContextWrapper myWrappedWorkerContext; private boolean errorForUnknownProfiles; private List myExtensionDomains = Collections.emptyList(); + private boolean assumeValidRestReferences; /** * Constructor @@ -285,10 +295,28 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta .setErrorForUnknownProfiles(isErrorForUnknownProfiles()) .setExtensionDomains(getExtensionDomains()) .setNoTerminologyChecks(isNoTerminologyChecks()) + .setValidatorResourceFetcher(getValidatorResourceFetcher()) + .setAssumeValidRestReferences(isAssumeValidRestReferences()) .validate(wrappedWorkerContext, theValidationCtx); } + public IResourceValidator.IValidatorResourceFetcher getValidatorResourceFetcher() { + return validatorResourceFetcher; + } + + public void setValidatorResourceFetcher(IResourceValidator.IValidatorResourceFetcher validatorResourceFetcher) { + this.validatorResourceFetcher = validatorResourceFetcher; + } + + public boolean isAssumeValidRestReferences() { + return assumeValidRestReferences; + } + + public void setAssumeValidRestReferences(boolean assumeValidRestReferences) { + this.assumeValidRestReferences = assumeValidRestReferences; + } + private static class WorkerContextWrapper implements IWorkerContext { private final HapiWorkerContext myWrap; @@ -327,6 +355,9 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta case "ImplementationGuide": fetched = myWrap.fetchResource(ImplementationGuide.class, key.getUri()); break; + case "SearchParameter": + fetched = myWrap.fetchResource(SearchParameter.class, key.getUri()); + break; default: throw new UnsupportedOperationException("Don't know how to fetch " + key.getResourceName()); } @@ -386,7 +417,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta retVal = new ArrayList<>(); for (StructureDefinition next : myWrap.allStructures()) { try { - retVal.add(VersionConvertor_30_50.convertStructureDefinition(next)); + retVal.add(convertStructureDefinition(next)); } catch (FHIRException e) { throw new InternalErrorException(e); } @@ -416,7 +447,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent conceptDefinition = null; if (theResult.asConceptDefinition() != null) { try { - conceptDefinition = VersionConvertor_30_50.convertConceptDefinitionComponent(theResult.asConceptDefinition()); + conceptDefinition = convertConceptDefinitionComponent(theResult.asConceptDefinition()); } catch (FHIRException e) { throw new InternalErrorException(e); } @@ -436,7 +467,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta public ValueSetExpander.ValueSetExpansionOutcome expandVS(org.hl7.fhir.r5.model.ValueSet source, boolean cacheOk, boolean heiarchical) { ValueSet convertedSource; try { - convertedSource = VersionConvertor_30_50.convertValueSet(source); + convertedSource = convertValueSet(source); } catch (FHIRException e) { throw new InternalErrorException(e); } @@ -445,7 +476,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta org.hl7.fhir.r5.model.ValueSet convertedResult = null; if (expanded.getValueset() != null) { try { - convertedResult = VersionConvertor_30_50.convertValueSet(expanded.getValueset()); + convertedResult = convertValueSet(expanded.getValueset()); } catch (FHIRException e) { throw new InternalErrorException(e); } @@ -467,7 +498,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta ValueSet.ConceptSetComponent convertedInc = null; if (inc != null) { try { - convertedInc = VersionConvertor_30_50.convertConceptSetComponent(inc); + convertedInc = convertConceptSetComponent(inc); } catch (FHIRException e) { throw new InternalErrorException(e); } @@ -477,7 +508,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionComponent valueSetExpansionComponent = null; if (expansion != null) { try { - valueSetExpansionComponent = VersionConvertor_30_50.convertValueSetExpansionComponent(expansion); + valueSetExpansionComponent = convertValueSetExpansionComponent(expansion); } catch (FHIRException e) { throw new InternalErrorException(e); } @@ -495,7 +526,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta return null; } try { - return VersionConvertor_30_50.convertCodeSystem(fetched); + return convertCodeSystem(fetched); } catch (FHIRException e) { throw new InternalErrorException(e); } @@ -584,6 +615,11 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta return fetchResource(org.hl7.fhir.r5.model.StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + typeName); } + @Override + public org.hl7.fhir.r5.model.StructureDefinition fetchRawProfile(String url) { + return fetchResource(org.hl7.fhir.r5.model.StructureDefinition.class, url); + } + @Override public List getTypeNames() { return myWrap.getTypeNames(); @@ -676,7 +712,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta try { if (vs != null) { - convertedVs = VersionConvertor_30_50.convertValueSet(vs); + convertedVs = convertValueSet(vs); } } catch (FHIRException e) { throw new InternalErrorException(e); @@ -691,7 +727,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta ValueSet convertedVs = null; try { if (vs != null) { - convertedVs = VersionConvertor_30_50.convertValueSet(vs); + convertedVs = convertValueSet(vs); } } catch (FHIRException e) { throw new InternalErrorException(e); @@ -711,7 +747,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta convertedCode = VersionConvertor_30_50.convertCoding(code); } if (vs != null) { - convertedVs = VersionConvertor_30_50.convertValueSet(vs); + convertedVs = convertValueSet(vs); } } catch (FHIRException e) { throw new InternalErrorException(e); @@ -731,7 +767,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta convertedCode = VersionConvertor_30_50.convertCodeableConcept(code); } if (vs != null) { - convertedVs = VersionConvertor_30_50.convertValueSet(vs); + convertedVs = convertValueSet(vs); } } catch (FHIRException e) { throw new InternalErrorException(e); diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/instance/hapi/validation/FhirInstanceValidator.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/instance/hapi/validation/FhirInstanceValidator.java index a92e2a957af..877c9cfa880 100644 --- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/instance/hapi/validation/FhirInstanceValidator.java +++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/instance/hapi/validation/FhirInstanceValidator.java @@ -27,12 +27,13 @@ import org.fhir.ucum.UcumService; import org.hl7.fhir.converter.NullVersionConverterAdvisor50; import org.hl7.fhir.convertors.VersionConvertorAdvisor50; import org.hl7.fhir.convertors.VersionConvertor_10_50; +import org.hl7.fhir.convertors.conv10_50.ValueSet10_50; +import org.hl7.fhir.convertors.conv14_50.CodeSystem14_50; import org.hl7.fhir.dstu2.model.CodeableConcept; import org.hl7.fhir.dstu2.model.Coding; import org.hl7.fhir.dstu2.model.Questionnaire; import org.hl7.fhir.dstu2.model.StructureDefinition; import org.hl7.fhir.dstu2.model.ValueSet; -import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.TerminologyServiceException; import org.hl7.fhir.r5.context.IWorkerContext; @@ -60,6 +61,7 @@ import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -69,6 +71,11 @@ import java.util.Set; import java.util.concurrent.TimeUnit; import static org.apache.commons.lang3.StringUtils.isBlank; +import static org.hl7.fhir.convertors.VersionConvertor_10_50.convertCoding; +import static org.hl7.fhir.convertors.conv10_50.StructureDefinition10_50.convertStructureDefinition; +import static org.hl7.fhir.convertors.conv10_50.ValueSet10_50.convertConceptSetComponent; +import static org.hl7.fhir.convertors.conv10_50.ValueSet10_50.convertValueSet; +import static org.hl7.fhir.convertors.conv10_50.ValueSet10_50.convertValueSetExpansionComponent; public class FhirInstanceValidator extends BaseValidatorBridge implements IInstanceValidatorModule { @@ -81,8 +88,19 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta private StructureDefinition myStructureDefintion; private IValidationSupport myValidationSupport; private boolean noTerminologyChecks = false; + + public boolean isAssumeValidRestReferences() { + return assumeValidRestReferences; + } + + public void setAssumeValidRestReferences(boolean assumeValidRestReferences) { + this.assumeValidRestReferences = assumeValidRestReferences; + } + + private boolean assumeValidRestReferences; private volatile WorkerContextWrapper myWrappedWorkerContext; private VersionConvertorAdvisor50 myAdvisor = new NullVersionConverterAdvisor50(); + private IResourceValidator.IValidatorResourceFetcher validatorResourceFetcher; /** * Constructor @@ -287,6 +305,8 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta v.setAnyExtensionsAllowed(isAnyExtensionsAllowed()); v.setResourceIdRule(IdStatus.OPTIONAL); v.setNoTerminologyChecks(isNoTerminologyChecks()); + v.setFetcher(getValidatorResourceFetcher()); + v.setAssumeValidRestReferences(isAssumeValidRestReferences()); List messages = new ArrayList<>(); @@ -388,6 +408,14 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta return messages; } + public IResourceValidator.IValidatorResourceFetcher getValidatorResourceFetcher() { + return validatorResourceFetcher; + } + + public void setValidatorResourceFetcher(IResourceValidator.IValidatorResourceFetcher validatorResourceFetcher) { + this.validatorResourceFetcher = validatorResourceFetcher; + } + @Override protected List validate(IValidationContext theCtx) { return validate(theCtx.getFhirContext(), theCtx.getResourceAsString(), theCtx.getResourceAsStringEncoding()); @@ -428,7 +456,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta return null; } } - profileText = IOUtils.toString(inputStream, "UTF-8"); + profileText = IOUtils.toString(inputStream, StandardCharsets.UTF_8); } catch (IOException e1) { if (theMessages != null) { theMessages.add(new ValidationMessage().setLevel(IssueSeverity.FATAL) @@ -457,11 +485,17 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta case "StructureDefinition": fetched = myWrap.fetchResource(StructureDefinition.class, key.getUri()); break; + case "CodeSystem": case "ValueSet": fetched = myWrap.fetchResource(ValueSet.class, key.getUri()); - break; - case "CodeSystem": - fetched = myWrap.fetchResource(ValueSet.class, key.getUri()); + + ValueSet fetchedVs = (ValueSet) fetched; + if (!fetchedVs.hasCompose()) { + if (fetchedVs.hasCodeSystem()) { + fetchedVs.getCompose().addInclude().setSystem(fetchedVs.getCodeSystem().getSystem()); + } + } + break; case "Questionnaire": fetched = myWrap.fetchResource(Questionnaire.class, key.getUri()); @@ -477,7 +511,15 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta } try { - org.hl7.fhir.r5.model.Resource converted = new VersionConvertor_10_50(myAdvisor).convertResource(fetched); + org.hl7.fhir.r5.model.Resource converted; + if ("CodeSystem".equals(key.getUri())) { + NullVersionConverterAdvisor50 advisor = new NullVersionConverterAdvisor50(); + converted = ValueSet10_50.convertValueSet((ValueSet) fetched, advisor); + converted = advisor.getCodeSystem((org.hl7.fhir.r5.model.ValueSet) converted); + } else { + converted = VersionConvertor_10_50.convertResource(fetched); + } + if (fetched instanceof StructureDefinition) { StructureDefinition fetchedSd = (StructureDefinition) fetched; @@ -501,7 +543,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta public WorkerContextWrapper(HapiWorkerContext theWorkerContext) { myWrap = theWorkerContext; - myConverter = new VersionConvertor_10_50(myAdvisor); + myConverter = new VersionConvertor_10_50(); } @Override @@ -510,7 +552,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta } @Override - public void generateSnapshot(org.hl7.fhir.r5.model.StructureDefinition p) throws DefinitionException, FHIRException { + public void generateSnapshot(org.hl7.fhir.r5.model.StructureDefinition p) throws FHIRException { } @@ -547,7 +589,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta retVal = new ArrayList<>(); for (StructureDefinition next : myWrap.allStructures()) { try { - org.hl7.fhir.r5.model.StructureDefinition converted = new VersionConvertor_10_50(myAdvisor).convertStructureDefinition(next); + org.hl7.fhir.r5.model.StructureDefinition converted = convertStructureDefinition(next); if (converted != null) { retVal.add(converted); } @@ -587,7 +629,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta public ValueSetExpander.ValueSetExpansionOutcome expandVS(org.hl7.fhir.r5.model.ValueSet source, boolean cacheOk, boolean heiarchical) { ValueSet convertedSource = null; try { - convertedSource = new VersionConvertor_10_50(myAdvisor).convertValueSet(source); + convertedSource = convertValueSet(source); } catch (FHIRException e) { throw new InternalErrorException(e); } @@ -596,7 +638,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta org.hl7.fhir.r5.model.ValueSet convertedResult = null; if (expanded.getValueset() != null) { try { - convertedResult = new VersionConvertor_10_50(myAdvisor).convertValueSet(expanded.getValueset()); + convertedResult = convertValueSet(expanded.getValueset()); } catch (FHIRException e) { throw new InternalErrorException(e); } @@ -618,7 +660,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta ValueSet.ConceptSetComponent convertedInc = null; if (inc != null) { try { - convertedInc = new VersionConvertor_10_50(myAdvisor).convertConceptSetComponent(inc); + convertedInc = convertConceptSetComponent(inc); } catch (FHIRException e) { throw new InternalErrorException(e); } @@ -628,7 +670,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionComponent valueSetExpansionComponent = null; if (expansion != null) { try { - valueSetExpansionComponent = new VersionConvertor_10_50(myAdvisor).convertValueSetExpansionComponent(expansion); + valueSetExpansionComponent = convertValueSetExpansionComponent(expansion); } catch (FHIRException e) { throw new InternalErrorException(e); } @@ -733,6 +775,11 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta return fetchResource(org.hl7.fhir.r5.model.StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/"+typeName); } + @Override + public org.hl7.fhir.r5.model.StructureDefinition fetchRawProfile(String url) { + return fetchResource(org.hl7.fhir.r5.model.StructureDefinition.class, url); + } + @Override public void setUcumService(UcumService ucumService) { throw new UnsupportedOperationException(); @@ -825,7 +872,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta try { if (vs != null) { - convertedVs = new VersionConvertor_10_50(myAdvisor).convertValueSet(vs); + convertedVs = convertValueSet(vs); } } catch (FHIRException e) { throw new InternalErrorException(e); @@ -840,8 +887,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta ValueSet convertedVs = null; try { if (vs != null) { - VersionConvertorAdvisor50 advisor50 = new NullVersionConverterAdvisor50(); - convertedVs = new VersionConvertor_10_50(advisor50).convertValueSet(vs); + convertedVs = convertValueSet(vs); } } catch (FHIRException e) { throw new InternalErrorException(e); @@ -858,10 +904,10 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta try { if (code != null) { - convertedCode = new VersionConvertor_10_50(myAdvisor).convertCoding(code); + convertedCode = convertCoding(code); } if (vs != null) { - convertedVs = new VersionConvertor_10_50(myAdvisor).convertValueSet(vs); + convertedVs = convertValueSet(vs); } } catch (FHIRException e) { throw new InternalErrorException(e); @@ -878,10 +924,10 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta try { if (code != null) { - convertedCode = new VersionConvertor_10_50(myAdvisor).convertCodeableConcept(code); + convertedCode = VersionConvertor_10_50.convertCodeableConcept(code); } if (vs != null) { - convertedVs = new VersionConvertor_10_50(myAdvisor).convertValueSet(vs); + convertedVs = convertValueSet(vs); } } catch (FHIRException e) { throw new InternalErrorException(e); diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/instance/hapi/validation/HapiWorkerContext.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/instance/hapi/validation/HapiWorkerContext.java index 9cdae210cd8..1788fd582a5 100644 --- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/instance/hapi/validation/HapiWorkerContext.java +++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/instance/hapi/validation/HapiWorkerContext.java @@ -199,7 +199,7 @@ public final class HapiWorkerContext implements IWorkerContext, ValueSetExpander nextSystem = nextComposeConceptSet.getSystem(); } - if (StringUtils.equals(nextSystem, nextComposeConceptSet.getSystem())) { + if (Constants.codeSystemNotNeeded(theSystem) || StringUtils.equals(nextSystem, nextComposeConceptSet.getSystem())) { for (ConceptReferenceComponent nextComposeCode : nextComposeConceptSet.getConcept()) { ConceptDefinitionComponent conceptDef = new ConceptDefinitionComponent(); conceptDef.setCode(nextComposeCode.getCode()); @@ -211,7 +211,13 @@ public final class HapiWorkerContext implements IWorkerContext, ValueSetExpander } if (nextComposeConceptSet.getConcept().isEmpty()){ - ValidationResult result = validateCode(nextSystem, theCode, null); + + String validateSystem = nextSystem; + if (Constants.codeSystemNotNeeded(nextSystem)) { + validateSystem = nextComposeConceptSet.getSystem(); + } + + ValidationResult result = validateCode(validateSystem, theCode, null); if (result.isOk()){ return result; } diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/r4/hapi/validation/FhirInstanceValidator.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/r4/hapi/validation/FhirInstanceValidator.java index d7c52d229a1..d5441294501 100644 --- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/r4/hapi/validation/FhirInstanceValidator.java +++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/r4/hapi/validation/FhirInstanceValidator.java @@ -59,7 +59,8 @@ public class FhirInstanceValidator extends org.hl7.fhir.r4.hapi.validation.BaseV private IValidationSupport myValidationSupport; private boolean noTerminologyChecks = false; private volatile WorkerContextWrapper myWrappedWorkerContext; - + private IResourceValidator.IValidatorResourceFetcher validatorResourceFetcher; + private boolean assumeValidRestReferences; private boolean errorForUnknownProfiles; private List extensionDomains = Collections.emptyList(); @@ -225,13 +226,32 @@ public class FhirInstanceValidator extends org.hl7.fhir.r4.hapi.validation.BaseV .setErrorForUnknownProfiles(isErrorForUnknownProfiles()) .setExtensionDomains(getExtensionDomains()) .setNoTerminologyChecks(isNoTerminologyChecks()) + .setValidatorResourceFetcher(getValidatorResourceFetcher()) + .setAssumeValidRestReferences(isAssumeValidRestReferences()) .validate(wrappedWorkerContext, theValidationCtx); } + public IResourceValidator.IValidatorResourceFetcher getValidatorResourceFetcher() { + return validatorResourceFetcher; + } + + public void setValidatorResourceFetcher(IResourceValidator.IValidatorResourceFetcher validatorResourceFetcher) { + this.validatorResourceFetcher = validatorResourceFetcher; + } + + private List getExtensionDomains() { return extensionDomains; } + public boolean isAssumeValidRestReferences() { + return assumeValidRestReferences; + } + + public void setAssumeValidRestReferences(boolean assumeValidRestReferences) { + this.assumeValidRestReferences = assumeValidRestReferences; + } + private static class WorkerContextWrapper implements IWorkerContext { private final HapiWorkerContext myWrap; @@ -317,7 +337,7 @@ public class FhirInstanceValidator extends org.hl7.fhir.r4.hapi.validation.BaseV retVal = new ArrayList<>(); for (StructureDefinition next : myWrap.allStructures()) { try { - retVal.add(org.hl7.fhir.convertors.conv40_50.StructureDefinition.convertStructureDefinition(next)); + retVal.add(org.hl7.fhir.convertors.conv40_50.StructureDefinition40_50.convertStructureDefinition(next)); } catch (FHIRException e) { throw new InternalErrorException(e); } @@ -347,7 +367,7 @@ public class FhirInstanceValidator extends org.hl7.fhir.r4.hapi.validation.BaseV org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent conceptDefinition = null; if (theResult.asConceptDefinition() != null) { try { - conceptDefinition = org.hl7.fhir.convertors.conv40_50.CodeSystem.convertConceptDefinitionComponent(theResult.asConceptDefinition()); + conceptDefinition = org.hl7.fhir.convertors.conv40_50.CodeSystem40_50.convertConceptDefinitionComponent(theResult.asConceptDefinition()); } catch (FHIRException e) { throw new InternalErrorException(e); } @@ -367,7 +387,7 @@ public class FhirInstanceValidator extends org.hl7.fhir.r4.hapi.validation.BaseV public ValueSetExpander.ValueSetExpansionOutcome expandVS(org.hl7.fhir.r5.model.ValueSet source, boolean cacheOk, boolean heiarchical) { ValueSet convertedSource; try { - convertedSource = org.hl7.fhir.convertors.conv40_50.ValueSet.convertValueSet(source); + convertedSource = org.hl7.fhir.convertors.conv40_50.ValueSet40_50.convertValueSet(source); } catch (FHIRException e) { throw new InternalErrorException(e); } @@ -376,7 +396,7 @@ public class FhirInstanceValidator extends org.hl7.fhir.r4.hapi.validation.BaseV org.hl7.fhir.r5.model.ValueSet convertedResult = null; if (expanded.getValueset() != null) { try { - convertedResult = org.hl7.fhir.convertors.conv40_50.ValueSet.convertValueSet(expanded.getValueset()); + convertedResult = org.hl7.fhir.convertors.conv40_50.ValueSet40_50.convertValueSet(expanded.getValueset()); } catch (FHIRException e) { throw new InternalErrorException(e); } @@ -398,7 +418,7 @@ public class FhirInstanceValidator extends org.hl7.fhir.r4.hapi.validation.BaseV ValueSet.ConceptSetComponent convertedInc = null; if (inc != null) { try { - convertedInc = org.hl7.fhir.convertors.conv40_50.ValueSet.convertConceptSetComponent(inc); + convertedInc = org.hl7.fhir.convertors.conv40_50.ValueSet40_50.convertConceptSetComponent(inc); } catch (FHIRException e) { throw new InternalErrorException(e); } @@ -408,7 +428,7 @@ public class FhirInstanceValidator extends org.hl7.fhir.r4.hapi.validation.BaseV org.hl7.fhir.r5.model.ValueSet valueSetExpansion = null; if (expansion != null) { try { - valueSetExpansion = org.hl7.fhir.convertors.conv40_50.ValueSet.convertValueSet(expansion.getValueset()); + valueSetExpansion = org.hl7.fhir.convertors.conv40_50.ValueSet40_50.convertValueSet(expansion.getValueset()); } catch (FHIRException e) { throw new InternalErrorException(e); } @@ -424,7 +444,7 @@ public class FhirInstanceValidator extends org.hl7.fhir.r4.hapi.validation.BaseV return null; } try { - return org.hl7.fhir.convertors.conv40_50.CodeSystem.convertCodeSystem(fetched); + return org.hl7.fhir.convertors.conv40_50.CodeSystem40_50.convertCodeSystem(fetched); } catch (FHIRException e) { throw new InternalErrorException(e); } @@ -509,6 +529,11 @@ public class FhirInstanceValidator extends org.hl7.fhir.r4.hapi.validation.BaseV return fetchResource(org.hl7.fhir.r5.model.StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + typeName); } + @Override + public org.hl7.fhir.r5.model.StructureDefinition fetchRawProfile(String url) { + return fetchResource(org.hl7.fhir.r5.model.StructureDefinition.class, url); + } + @Override public List getTypeNames() { return myWrap.getTypeNames(); @@ -605,7 +630,7 @@ public class FhirInstanceValidator extends org.hl7.fhir.r4.hapi.validation.BaseV try { if (vs != null) { - convertedVs = org.hl7.fhir.convertors.conv40_50.ValueSet.convertValueSet(vs); + convertedVs = org.hl7.fhir.convertors.conv40_50.ValueSet40_50.convertValueSet(vs); } } catch (FHIRException e) { throw new InternalErrorException(e); @@ -620,7 +645,7 @@ public class FhirInstanceValidator extends org.hl7.fhir.r4.hapi.validation.BaseV ValueSet convertedVs = null; try { if (vs != null) { - convertedVs = org.hl7.fhir.convertors.conv40_50.ValueSet.convertValueSet(vs); + convertedVs = org.hl7.fhir.convertors.conv40_50.ValueSet40_50.convertValueSet(vs); } } catch (FHIRException e) { throw new InternalErrorException(e); @@ -640,7 +665,7 @@ public class FhirInstanceValidator extends org.hl7.fhir.r4.hapi.validation.BaseV convertedCode = VersionConvertor_40_50.convertCoding(code); } if (vs != null) { - convertedVs = org.hl7.fhir.convertors.conv40_50.ValueSet.convertValueSet(vs); + convertedVs = org.hl7.fhir.convertors.conv40_50.ValueSet40_50.convertValueSet(vs); } } catch (FHIRException e) { throw new InternalErrorException(e); @@ -660,7 +685,7 @@ public class FhirInstanceValidator extends org.hl7.fhir.r4.hapi.validation.BaseV convertedCode = VersionConvertor_40_50.convertCodeableConcept(code); } if (vs != null) { - convertedVs = org.hl7.fhir.convertors.conv40_50.ValueSet.convertValueSet(vs); + convertedVs = org.hl7.fhir.convertors.conv40_50.ValueSet40_50.convertValueSet(vs); } } catch (FHIRException e) { throw new InternalErrorException(e); diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/r5/hapi/validation/FhirInstanceValidator.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/r5/hapi/validation/FhirInstanceValidator.java index 02a3fd839d2..a6ced0b4654 100644 --- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/r5/hapi/validation/FhirInstanceValidator.java +++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/r5/hapi/validation/FhirInstanceValidator.java @@ -54,7 +54,9 @@ public class FhirInstanceValidator extends org.hl7.fhir.r5.hapi.validation.BaseV private boolean noTerminologyChecks = false; private volatile WorkerContextWrapper myWrappedWorkerContext; private boolean errorForUnknownProfiles; + private boolean assumeValidRestReferences; private List myExtensionDomains = Collections.emptyList(); + private IResourceValidator.IValidatorResourceFetcher validatorResourceFetcher; /** * Constructor @@ -220,9 +222,27 @@ public class FhirInstanceValidator extends org.hl7.fhir.r5.hapi.validation.BaseV .setErrorForUnknownProfiles(isErrorForUnknownProfiles()) .setExtensionDomains(getExtensionDomains()) .setNoTerminologyChecks(isNoTerminologyChecks()) + .setValidatorResourceFetcher(getValidatorResourceFetcher()) + .setAssumeValidRestReferences(isAssumeValidRestReferences()) .validate(wrappedWorkerContext, theValidationCtx); } + public IResourceValidator.IValidatorResourceFetcher getValidatorResourceFetcher() { + return validatorResourceFetcher; + } + + public void setValidatorResourceFetcher(IResourceValidator.IValidatorResourceFetcher validatorResourceFetcher) { + this.validatorResourceFetcher = validatorResourceFetcher; + } + + public boolean isAssumeValidRestReferences() { + return assumeValidRestReferences; + } + + public void setAssumeValidRestReferences(boolean assumeValidRestReferences) { + this.assumeValidRestReferences = assumeValidRestReferences; + } + private static class WorkerContextWrapper implements IWorkerContext { private final HapiWorkerContext myWrap; @@ -514,6 +534,11 @@ public class FhirInstanceValidator extends org.hl7.fhir.r5.hapi.validation.BaseV return fetchResource(org.hl7.fhir.r5.model.StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + typeName); } + @Override + public StructureDefinition fetchRawProfile(String url) { + return myWrap.fetchRawProfile(url); + } + @Override public List getTypeNames() { return myWrap.getTypeNames(); @@ -706,7 +731,7 @@ public class FhirInstanceValidator extends org.hl7.fhir.r5.hapi.validation.BaseV } @Override - public Base resolveReference(Object appContext, String url) throws FHIRException { + public Base resolveReference(Object appContext, String url, Base refContext) throws FHIRException { return null; } diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/FhirInstanceValidatorDstu3Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/FhirInstanceValidatorDstu3Test.java index bace1c7268e..29fbca55962 100644 --- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/FhirInstanceValidatorDstu3Test.java +++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/FhirInstanceValidatorDstu3Test.java @@ -24,10 +24,12 @@ import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent; import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionComponent; import org.hl7.fhir.dstu3.utils.FHIRPathEngine; import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.r5.utils.IResourceValidator; import org.junit.*; import org.junit.rules.TestRule; import org.junit.rules.TestWatcher; import org.junit.runner.Description; +import org.mockito.internal.matchers.Any; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; @@ -41,8 +43,7 @@ import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; public class FhirInstanceValidatorDstu3Test { @@ -975,7 +976,7 @@ public class FhirInstanceValidatorDstu3Test { myInstanceVal.setValidationSupport(myMockSupport); ValidationResult output = myVal.validateWithResult(input); List errors = logResultsAndReturnNonInformationalOnes(output); - assertThat(errors.toString(), containsString("StructureDefinition reference \"http://foo/structuredefinition/myprofile\" could not be resolved")); + assertThat(errors.toString(), containsString("Profile reference 'http://foo/structuredefinition/myprofile' could not be resolved, so has not been checked")); } @Test @@ -1145,6 +1146,20 @@ public class FhirInstanceValidatorDstu3Test { ourLog.info(output.getMessages().get(0).getMessage()); } + @Test + public void testInvocationOfValidatorFetcher() throws IOException { + String input = IOUtils.toString(FhirInstanceValidatorDstu3Test.class.getResourceAsStream("/dstu3-rick-test.json"), Charsets.UTF_8); + + IResourceValidator.IValidatorResourceFetcher resourceFetcher = mock(IResourceValidator.IValidatorResourceFetcher.class); + when(resourceFetcher.validationPolicy(any(),anyString(), anyString())).thenReturn(IResourceValidator.ReferenceValidationPolicy.CHECK_TYPE_IF_EXISTS); + myInstanceVal.setValidatorResourceFetcher(resourceFetcher); + myVal.validateWithResult(input); + + verify(resourceFetcher, times(3)).resolveURL(any(), anyString(), anyString()); + verify(resourceFetcher, times(4)).validationPolicy(any(), anyString(), anyString()); + verify(resourceFetcher, times(4)).fetch(any(), anyString()); + } + @Test public void testValueWithWhitespace() throws IOException { String input = IOUtils.toString(FhirInstanceValidatorDstu3Test.class.getResourceAsStream("/dstu3-rick-test.json"), Charsets.UTF_8); diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/QuestionnaireResponseValidatorDstu3Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/QuestionnaireResponseValidatorDstu3Test.java index d4bbfac740e..7cbd9968f1e 100644 --- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/QuestionnaireResponseValidatorDstu3Test.java +++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/QuestionnaireResponseValidatorDstu3Test.java @@ -704,7 +704,7 @@ public class QuestionnaireResponseValidatorDstu3Test { coding.setCode("1293"); QuestionnaireResponseItemAnswerComponent answer = qrItem.addAnswer(); answer.setValue(coding); - coding.addExtension("http://hl7.org/fhir/StructureDefinition/questionnaire-hidden", new BooleanType(true)); + coding.addExtension("http://hl7.org/fhir/StructureDefinition/iso21090-CO-value", new DecimalType("1.0")); qr.addItem().setLinkId("2B").addAnswer().setValue(new BooleanType(true)); String reference = qr.getQuestionnaire().getReference(); diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/QuestionnaireValidatorDstu3Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/QuestionnaireValidatorDstu3Test.java index 4a8ececb99a..9e8a25f5a42 100644 --- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/QuestionnaireValidatorDstu3Test.java +++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/QuestionnaireValidatorDstu3Test.java @@ -20,6 +20,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Collections; +import java.util.stream.Collectors; import static org.hamcrest.CoreMatchers.containsString; import static org.junit.Assert.assertEquals; @@ -71,7 +72,7 @@ public class QuestionnaireValidatorDstu3Test { ValidationResult errors = myVal.validateWithResult(q); ourLog.info(errors.toString()); assertThat(errors.isSuccessful(), Matchers.is(true)); - assertThat(errors.getMessages(), Matchers.empty()); + assertThat(errors.getMessages().stream().filter(t->t.getSeverity().ordinal() > ResultSeverityEnum.INFORMATION.ordinal()).collect(Collectors.toList()), Matchers.empty()); } } diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/FhirInstanceValidatorR4Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/FhirInstanceValidatorR4Test.java index ce094c1a8a8..fe617e9b955 100644 --- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/FhirInstanceValidatorR4Test.java +++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/FhirInstanceValidatorR4Test.java @@ -66,9 +66,10 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.nullable; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.*; +import static org.mockito.Mockito.times; public class FhirInstanceValidatorR4Test extends BaseTest { @@ -397,7 +398,11 @@ public class FhirInstanceValidatorR4Test extends BaseTest { ValidationResult output = myVal.validateWithResult(encoded); List errors = logResultsAndReturnNonInformationalOnes(output); - assertEquals(46, errors.size()); + errors = errors + .stream() + .filter(t->t.getMessage().contains("Bundle entry missing fullUrl")) + .collect(Collectors.toList()); + assertEquals(5, errors.size()); } @Test @@ -633,8 +638,8 @@ public class FhirInstanceValidatorR4Test extends BaseTest { CachingValidationSupport support = new CachingValidationSupport(new ValidationSupportChain(defaultSupport, valSupport)); // Prepopulate SDs - valSupport.addStructureDefinition(loadStructureDefinition(defaultSupport, "/dstu3/myconsent-profile.xml")); - valSupport.addStructureDefinition(loadStructureDefinition(defaultSupport, "/dstu3/myconsent-ext.xml")); + valSupport.addStructureDefinition(loadStructureDefinition(defaultSupport, "/r4/myconsent-profile.xml")); + valSupport.addStructureDefinition(loadStructureDefinition(defaultSupport, "/r4/myconsent-ext.xml")); FhirValidator val = ourCtx.newValidator(); val.registerValidatorModule(new FhirInstanceValidator(support)); @@ -652,6 +657,8 @@ public class FhirInstanceValidatorR4Test extends BaseTest { .setSystem("http://terminology.hl7.org/CodeSystem/consentcategorycodes") .setCode("acd"); + + // Should pass ValidationResult output = val.validateWithResult(input); List all = logResultsAndReturnErrorOnes(output); @@ -1031,7 +1038,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest { myInstanceVal.setValidationSupport(myMockSupport); ValidationResult output = myVal.validateWithResult(input); List errors = logResultsAndReturnNonInformationalOnes(output); - assertThat(errors.toString(), containsString("StructureDefinition reference \"http://foo/structuredefinition/myprofile\" could not be resolved")); + assertThat(errors.toString(), containsString("Profile reference 'http://foo/structuredefinition/myprofile' could not be resolved, so has not been checked")); } @Test @@ -1250,6 +1257,21 @@ public class FhirInstanceValidatorR4Test extends BaseTest { assertEquals(0, all.size()); } + @Test + public void testInvocationOfValidatorFetcher() throws IOException { + + String encoded = loadResource("/r4/r4-caredove-bundle.json"); + + IResourceValidator.IValidatorResourceFetcher resourceFetcher = mock(IResourceValidator.IValidatorResourceFetcher.class); + when(resourceFetcher.validationPolicy(any(),anyString(), anyString())).thenReturn(IResourceValidator.ReferenceValidationPolicy.CHECK_TYPE_IF_EXISTS); + myInstanceVal.setValidatorResourceFetcher(resourceFetcher); + myVal.validateWithResult(encoded); + + verify(resourceFetcher, times(14)).resolveURL(any(), anyString(), anyString()); + verify(resourceFetcher, times(12)).validationPolicy(any(), anyString(), anyString()); + verify(resourceFetcher, times(12)).fetch(any(), anyString()); + } + @Test @Ignore public void testValidateStructureDefinition() throws IOException { diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/QuestionnaireValidatorR4Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/QuestionnaireValidatorR4Test.java index b6b88d44c15..ff872af31f4 100644 --- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/QuestionnaireValidatorR4Test.java +++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/QuestionnaireValidatorR4Test.java @@ -23,6 +23,8 @@ import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.stream.Collectors; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; @@ -72,7 +74,7 @@ public class QuestionnaireValidatorR4Test { ValidationResult errors = myVal.validateWithResult(q); ourLog.info(errors.toString()); assertThat(errors.isSuccessful(), Matchers.is(true)); - assertThat(errors.getMessages(), Matchers.empty()); + assertThat(errors.getMessages().stream().filter(t->t.getSeverity().ordinal() > ResultSeverityEnum.INFORMATION.ordinal()).collect(Collectors.toList()), Matchers.empty()); } } diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r5/validation/FhirInstanceValidatorR5Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r5/validation/FhirInstanceValidatorR5Test.java index 3a4380a3a20..05a8e54e3ff 100644 --- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r5/validation/FhirInstanceValidatorR5Test.java +++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r5/validation/FhirInstanceValidatorR5Test.java @@ -53,9 +53,10 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.nullable; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.*; +import static org.mockito.Mockito.times; public class FhirInstanceValidatorR5Test { @@ -415,6 +416,23 @@ public class FhirInstanceValidatorR5Test { assertThat(nonInfo, empty()); } + + + @Test + public void testInvocationOfValidatorFetcher() throws IOException { + + String input = IOUtils.toString(FhirInstanceValidator.class.getResourceAsStream("/vitals.json"), Charsets.UTF_8); + + IResourceValidator.IValidatorResourceFetcher resourceFetcher = mock(IResourceValidator.IValidatorResourceFetcher.class); + when(resourceFetcher.validationPolicy(any(),anyString(), anyString())).thenReturn(IResourceValidator.ReferenceValidationPolicy.CHECK_TYPE_IF_EXISTS); + myInstanceVal.setValidatorResourceFetcher(resourceFetcher); + myVal.validateWithResult(input); + + verify(resourceFetcher, times(12)).resolveURL(any(), anyString(), anyString()); + verify(resourceFetcher, times(3)).validationPolicy(any(), anyString(), anyString()); + verify(resourceFetcher, times(3)).fetch(any(), anyString()); + } + @Test public void testIsNoTerminologyChecks() { assertFalse(myInstanceVal.isNoTerminologyChecks()); @@ -774,7 +792,7 @@ public class FhirInstanceValidatorR5Test { myInstanceVal.setValidationSupport(myMockSupport); ValidationResult output = myVal.validateWithResult(input); List errors = logResultsAndReturnNonInformationalOnes(output); - assertThat(errors.toString(), containsString("StructureDefinition reference \"http://foo/structuredefinition/myprofile\" could not be resolved")); + assertThat(errors.toString(), containsString("Profile reference 'http://foo/structuredefinition/myprofile' could not be resolved, so has not been checked")); } @Test diff --git a/hapi-fhir-validation/src/test/resources/r4/myconsent-ext.xml b/hapi-fhir-validation/src/test/resources/r4/myconsent-ext.xml new file mode 100644 index 00000000000..2049e440b22 --- /dev/null +++ b/hapi-fhir-validation/src/test/resources/r4/myconsent-ext.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hapi-fhir-validation/src/test/resources/r4/myconsent-profile.xml b/hapi-fhir-validation/src/test/resources/r4/myconsent-profile.xml new file mode 100644 index 00000000000..0396797fe88 --- /dev/null +++ b/hapi-fhir-validation/src/test/resources/r4/myconsent-profile.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hapi-fhir-validation/src/test/resources/vitals.json b/hapi-fhir-validation/src/test/resources/vitals.json new file mode 100644 index 00000000000..78b3e733c6b --- /dev/null +++ b/hapi-fhir-validation/src/test/resources/vitals.json @@ -0,0 +1,97 @@ +{ + "resourceType": "Observation", + "id": "satO2", + "meta": { + "profile": [ + "http://hl7.org/fhir/StructureDefinition/vitalsigns" + ] + }, + "text": { + "status": "generated", + "div": "

Generated Narrative with Details

id: satO2

meta:

identifier: o1223435-10

partOf: Procedure/ob

status: final

category: Vital Signs (Details : {http://terminology.hl7.org/CodeSystem/observation-category code 'vital-signs' = 'Vital Signs', given as 'Vital Signs'})

code: Oxygen saturation in Arterial blood (Details : {LOINC code '2708-6' = 'Oxygen saturation in Arterial blood', given as 'Oxygen saturation in Arterial blood'}; {LOINC code '59408-5' = 'Oxygen saturation in Arterial blood by Pulse oximetry', given as 'Oxygen saturation in Arterial blood by Pulse oximetry'}; {urn:iso:std:iso:11073:10101 code '150456' = '150456', given as 'MDC_PULS_OXIM_SAT_O2'})

subject: Patient/example

effective: Dec 5, 2014 9:30:10 AM

value: 95 % (Details: UCUM code % = '%')

interpretation: Normal (applies to non-numeric results) (Details : {http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation code 'N' = 'Normal', given as 'Normal'})

device: DeviceMetric/example

ReferenceRanges

-LowHigh
*90 % (Details: UCUM code % = '%')99 % (Details: UCUM code % = '%')
" + }, + "identifier": [ + { + "system": "http://goodcare.org/observation/id", + "value": "o1223435-10" + } + ], + "partOf": [ + { + "reference": "Procedure/ob" + } + ], + "status": "final", + "category": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/observation-category", + "code": "vital-signs", + "display": "Vital Signs" + } + ], + "text": "Vital Signs" + } + ], + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "2708-6", + "display": "Oxygen saturation in Arterial blood" + }, + { + "system": "http://loinc.org", + "code": "59408-5", + "display": "Oxygen saturation in Arterial blood by Pulse oximetry" + }, + { + "system": "urn:iso:std:iso:11073:10101", + "code": "150456", + "display": "MDC_PULS_OXIM_SAT_O2" + } + ] + }, + "subject": { + "reference": "Patient/example" + }, + "effectiveDateTime": "2014-12-05T09:30:10+01:00", + "valueQuantity": { + "value": 95, + "unit": "%", + "system": "http://unitsofmeasure.org", + "code": "%" + }, + "interpretation": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation", + "code": "N", + "display": "Normal" + } + ], + "text": "Normal (applies to non-numeric results)" + } + ], + "device": { + "reference": "DeviceMetric/example" + }, + "referenceRange": [ + { + "low": { + "value": 90, + "unit": "%", + "system": "http://unitsofmeasure.org", + "code": "%" + }, + "high": { + "value": 99, + "unit": "%", + "system": "http://unitsofmeasure.org", + "code": "%" + } + } + ] +} diff --git a/pom.xml b/pom.xml index 495bc8afe38..ef8d1092440 100644 --- a/pom.xml +++ b/pom.xml @@ -606,7 +606,7 @@ - 4.2.0 + 4.2.1-SNAPSHOT 1.0.2 -Dfile.encoding=UTF-8 -Xmx2048m