R4B and R5 extension changes

This commit is contained in:
Grahame Grieve 2022-06-28 15:39:15 +03:00
parent 982ce5f58f
commit 023aea34fb
6 changed files with 165 additions and 99 deletions

View File

@ -127,12 +127,14 @@ import org.hl7.fhir.r5.utils.XVerExtensionManager.XVerExtensionStatus;
import org.hl7.fhir.r5.utils.formats.CSVWriter;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.MarkDownProcessor;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.i18n.I18nConstants;
import org.hl7.fhir.utilities.npm.BasePackageCacheManager;
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
import org.hl7.fhir.utilities.npm.NpmPackage;
import org.hl7.fhir.utilities.npm.PackageHacker;
import org.hl7.fhir.utilities.npm.NpmPackage.PackageResourceInformation;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
@ -6846,100 +6848,6 @@ public class ProfileUtilities extends TranslatingUtilities {
public void setMasterSourceFileNames(Set<String> masterSourceFileNames) {
this.masterSourceFileNames = masterSourceFileNames;
}
public static int loadR5Extensions(BasePackageCacheManager pcm, IWorkerContext context) throws FHIRException, IOException {
NpmPackage npm = pcm.loadPackage("hl7.fhir.r5.core", "current");
String[] types = new String[] { "StructureDefinition", "ValueSet", "CodeSystem" };
Map<String, ValueSet> valueSets = new HashMap<>();
Map<String, CodeSystem> codeSystems = new HashMap<>();
List<StructureDefinition> extensions = new ArrayList<>();
JsonParser json = new JsonParser();
for (PackageResourceInformation pri : npm.listIndexedResources(types)) {
CanonicalResource r = (CanonicalResource) json.parse(npm.load(pri));
if (r instanceof CodeSystem) {
codeSystems.put(r.getUrl(), (CodeSystem) r);
} else if (r instanceof ValueSet) {
valueSets.put(r.getUrl(), (ValueSet) r);
} else if (r instanceof StructureDefinition) {
extensions.add((StructureDefinition) r);
}
}
PackageVersion pd = new PackageVersion(npm.name(), npm.version(), npm.dateAsDate());
int c = 0;
List<String> typeNames = context.getTypeNames();
for (StructureDefinition sd : extensions) {
if (sd.getType().equals("Extension") && sd.getDerivation() == TypeDerivationRule.CONSTRAINT &&
!context.hasResource(StructureDefinition.class, sd.getUrl())) {
if (survivesStrippingTypes(sd, context, typeNames)) {
c++;
sd.setUserData("path", Utilities.pathURL(npm.getWebLocation(), "extension-"+sd.getId()+".html"));
context.cacheResourceFromPackage(sd, pd);
registerTerminologies(sd, context, valueSets, codeSystems, pd);
}
}
}
return c;
}
private static void registerTerminologies(StructureDefinition sd, IWorkerContext context, Map<String, ValueSet> valueSets, Map<String, CodeSystem> codeSystems, PackageVersion pd) {
for (ElementDefinition ed : sd.getSnapshot().getElement()) {
if (ed.hasBinding() && ed.getBinding().hasValueSet()) {
String vs = ed.getBinding().getValueSet();
if (!context.hasResource(StructureDefinition.class, vs)) {
loadValueSet(vs, context, valueSets, codeSystems, pd);
}
}
}
}
private static void loadValueSet(String url, IWorkerContext context, Map<String, ValueSet> valueSets, Map<String, CodeSystem> codeSystems, PackageVersion pd) {
if (valueSets.containsKey(url)) {
ValueSet vs = valueSets.get(url);
context.cacheResourceFromPackage(vs, pd);
for (ConceptSetComponent inc : vs.getCompose().getInclude()) {
for (CanonicalType t : inc.getValueSet()) {
loadValueSet(t.asStringValue(), context, valueSets, codeSystems, pd);
}
if (inc.hasSystem()) {
if (!context.hasResource(CodeSystem.class, inc.getSystem()) && codeSystems.containsKey(inc.getSystem())) {
context.cacheResourceFromPackage(codeSystems.get(inc.getSystem()), pd);
}
}
}
}
}
private static boolean survivesStrippingTypes(StructureDefinition sd, IWorkerContext context, List<String> typeNames) {
for (ElementDefinition ed : sd.getDifferential().getElement()) {
stripTypes(ed, context, typeNames);
}
for (ElementDefinition ed : sd.getSnapshot().getElement()) {
if (!stripTypes(ed, context, typeNames)) {
return false;
}
}
return true;
}
private static boolean stripTypes(ElementDefinition ed, IWorkerContext context, List<String> typeNames) {
if (!ed.getPath().contains(".") || !ed.hasType()) {
return true;
}
ed.getType().removeIf(tr -> !typeNames.contains(tr.getWorkingCode()));
if (!ed.hasType()) {
return false;
}
for (TypeRefComponent tr : ed.getType()) {
if (tr.hasTargetProfile()) {
tr.getTargetProfile().removeIf(n -> !context.hasResource(StructureDefinition.class, n.asStringValue()));
if (!tr.hasTargetProfile()) {
return false;
}
}
}
return true;
}
}

View File

@ -0,0 +1,153 @@
package org.hl7.fhir.r5.conformance;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.context.IWorkerContext.PackageVersion;
import org.hl7.fhir.r5.formats.JsonParser;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.CanonicalType;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent;
import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule;
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.npm.BasePackageCacheManager;
import org.hl7.fhir.utilities.npm.NpmPackage;
import org.hl7.fhir.utilities.npm.NpmPackage.PackageResourceInformation;
public class R5ExtensionsLoader {
private BasePackageCacheManager pcm;
private int count;
private byte[] map;
private NpmPackage pck;
public R5ExtensionsLoader(BasePackageCacheManager pcm) {
super();
this.pcm = pcm;
}
public void loadR5Extensions(IWorkerContext context) throws FHIRException, IOException {
pck = pcm.loadPackage("hl7.fhir.r5.core", "current");
String[] types = new String[] { "StructureDefinition", "ValueSet", "CodeSystem" };
Map<String, ValueSet> valueSets = new HashMap<>();
Map<String, CodeSystem> codeSystems = new HashMap<>();
List<StructureDefinition> extensions = new ArrayList<>();
JsonParser json = new JsonParser();
for (PackageResourceInformation pri : pck.listIndexedResources(types)) {
CanonicalResource r = (CanonicalResource) json.parse(pck.load(pri));
if (r instanceof CodeSystem) {
codeSystems.put(r.getUrl(), (CodeSystem) r);
} else if (r instanceof ValueSet) {
valueSets.put(r.getUrl(), (ValueSet) r);
} else if (r instanceof StructureDefinition) {
extensions.add((StructureDefinition) r);
}
}
PackageVersion pd = new PackageVersion(pck.name(), pck.version(), pck.dateAsDate());
count = 0;
List<String> typeNames = context.getTypeNames();
for (StructureDefinition sd : extensions) {
if (sd.getType().equals("Extension") && sd.getDerivation() == TypeDerivationRule.CONSTRAINT &&
!context.hasResource(StructureDefinition.class, sd.getUrl())) {
if (survivesStrippingTypes(sd, context, typeNames)) {
count++;
sd.setUserData("path", Utilities.pathURL(pck.getWebLocation(), "extension-"+sd.getId().toLowerCase()+".html"));
context.cacheResourceFromPackage(sd, pd);
registerTerminologies(sd, context, valueSets, codeSystems, pd);
}
}
}
map = pck.hasFile("other", "spec.internals") ? TextFile.streamToBytes(pck.load("other", "spec.internals")) : null;
}
private void registerTerminologies(StructureDefinition sd, IWorkerContext context, Map<String, ValueSet> valueSets, Map<String, CodeSystem> codeSystems, PackageVersion pd) {
for (ElementDefinition ed : sd.getSnapshot().getElement()) {
if (ed.hasBinding() && ed.getBinding().hasValueSet()) {
String vs = ed.getBinding().getValueSet();
if (!context.hasResource(StructureDefinition.class, vs)) {
loadValueSet(vs, context, valueSets, codeSystems, pd);
}
}
}
}
private void loadValueSet(String url, IWorkerContext context, Map<String, ValueSet> valueSets, Map<String, CodeSystem> codeSystems, PackageVersion pd) {
if (valueSets.containsKey(url)) {
ValueSet vs = valueSets.get(url);
context.cacheResourceFromPackage(vs, pd);
for (ConceptSetComponent inc : vs.getCompose().getInclude()) {
for (CanonicalType t : inc.getValueSet()) {
loadValueSet(t.asStringValue(), context, valueSets, codeSystems, pd);
}
if (inc.hasSystem()) {
if (!context.hasResource(CodeSystem.class, inc.getSystem()) && codeSystems.containsKey(inc.getSystem())) {
context.cacheResourceFromPackage(codeSystems.get(inc.getSystem()), pd);
}
}
}
}
}
private boolean survivesStrippingTypes(StructureDefinition sd, IWorkerContext context, List<String> typeNames) {
for (ElementDefinition ed : sd.getDifferential().getElement()) {
stripTypes(ed, context, typeNames);
}
for (ElementDefinition ed : sd.getSnapshot().getElement()) {
if (!stripTypes(ed, context, typeNames)) {
return false;
}
}
return true;
}
private boolean stripTypes(ElementDefinition ed, IWorkerContext context, List<String> typeNames) {
if (!ed.getPath().contains(".") || !ed.hasType()) {
return true;
}
ed.getType().removeIf(tr -> !typeNames.contains(tr.getWorkingCode()));
if (!ed.hasType()) {
return false;
}
for (TypeRefComponent tr : ed.getType()) {
if (tr.hasTargetProfile()) {
tr.getTargetProfile().removeIf(n -> !context.hasResource(StructureDefinition.class, n.asStringValue()));
if (!tr.hasTargetProfile()) {
return false;
}
}
}
return true;
}
public BasePackageCacheManager getPcm() {
return pcm;
}
public int getCount() {
return count;
}
public byte[] getMap() {
return map;
}
public NpmPackage getPck() {
return pck;
}
}

View File

@ -331,7 +331,8 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
if (Utilities.existsInList(url, "http://hl7.org/fhir/SearchParameter/example")) {
return;
}
throw new DefinitionException(formatMessage(I18nConstants.DUPLICATE_RESOURCE_, url));
throw new DefinitionException(formatMessage(I18nConstants.DUPLICATE_RESOURCE_, url,
fetchResourceWithException(r.getType(), url).fhirType()));
}
switch(r.getType()) {
case "StructureDefinition":
@ -412,7 +413,8 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
if (Utilities.existsInList(url, "http://hl7.org/fhir/SearchParameter/example")) {
return;
}
throw new DefinitionException(formatMessage(I18nConstants.DUPLICATE_RESOURCE_, url));
throw new DefinitionException(formatMessage(I18nConstants.DUPLICATE_RESOURCE_, url,
fetchResourceWithException(r.getClass(), url).fhirType()));
}
if (r instanceof StructureDefinition) {
StructureDefinition sd = (StructureDefinition) m;

View File

@ -416,7 +416,7 @@ No_Parameters_provided_to_expandVS = No Parameters provided to expandVS
No_Expansion_Parameters_provided = No Expansion Parameters provided
Unable_to_resolve_value_Set_ = Unable to resolve value Set {0}
Delimited_versions_have_exact_match_for_delimiter____vs_ = Delimited versions have exact match for delimiter ''{0}'' : {1} vs {2}
Duplicate_Resource_ = Duplicate Resource {0}
Duplicate_Resource_ = Duplicate Resource {0} of type {1}
Error_expanding_ValueSet_running_without_terminology_services = Error expanding ValueSet: running without terminology services
Error_validating_code_running_without_terminology_services = Error validating code: running without terminology services
Unable_to_validate_code_without_using_server = Unable to validate code without using server

View File

@ -5,6 +5,7 @@ import org.hl7.fhir.r5.context.SimpleWorkerContext;
import org.hl7.fhir.r5.context.SystemOutLoggingService;
import org.hl7.fhir.r5.context.TerminologyCache;
import org.hl7.fhir.r5.conformance.ProfileUtilities;
import org.hl7.fhir.r5.conformance.R5ExtensionsLoader;
import org.hl7.fhir.r5.context.IWorkerContext.PackageVersion;
import org.hl7.fhir.r5.context.SimpleWorkerContext.PackageResourceLoader;
import org.hl7.fhir.r5.elementmodel.Manager;
@ -341,7 +342,9 @@ public class ValidationService {
System.out.println(" - " + validator.getContext().countAllCaches() + " resources (" + tt.milestone() + ")");
igLoader.loadIg(validator.getIgs(), validator.getBinaries(), "hl7.terminology", false);
System.out.print(" Load R5 Extensions");
System.out.println(" - " + ProfileUtilities.loadR5Extensions(validator.getPcm(), validator.getContext()) + " resources (" + tt.milestone() + ")");
R5ExtensionsLoader r5e = new R5ExtensionsLoader(validator.getPcm());
r5e.loadR5Extensions(validator.getContext());
System.out.println(" - " + r5e.getCount() + " resources (" + tt.milestone() + ")");
System.out.print(" Terminology server " + cliContext.getTxServer());
String txver = validator.setTerminologyServer(cliContext.getTxServer(), cliContext.getTxLog(), ver);
System.out.println(" - Version " + txver + " (" + tt.milestone() + ")");

View File

@ -19,7 +19,7 @@
<properties>
<hapi_fhir_version>5.4.0</hapi_fhir_version>
<validator_test_case_version>1.1.102</validator_test_case_version>
<validator_test_case_version>1.1.103-SNAPSHOT</validator_test_case_version>
<junit_jupiter_version>5.7.1</junit_jupiter_version>
<junit_platform_launcher_version>1.8.2</junit_platform_launcher_version>
<maven_surefire_version>3.0.0-M5</maven_surefire_version>