mirror of
https://github.com/hapifhir/org.hl7.fhir.core.git
synced 2025-03-06 03:19:15 +00:00
Validate that ConceptMap references to ValueSets are actual value sets
and Validate that abstract classes have concrete subtypes
This commit is contained in:
parent
46e2d251d3
commit
0d6ce842b0
@ -10,10 +10,12 @@ public class ResourceSorters {
|
||||
|
||||
@Override
|
||||
public int compare(CanonicalResource arg0, CanonicalResource arg1) {
|
||||
if (arg0.getUrl() != null) {
|
||||
if (arg0.getUrl() != null && arg1.getUrl() != null) {
|
||||
return arg0.getUrl().compareTo(arg1.getUrl());
|
||||
} else if (arg1.getUrl() != null) {
|
||||
return -arg1.getUrl().compareTo(arg0.getUrl());
|
||||
return -1;
|
||||
} else if (arg0.getUrl() != null) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
@ -278,6 +278,8 @@ public class ToolingExtensions {
|
||||
public static final String EXT_ALTERNATE_CANONICAL = "http://hl7.org/fhir/StructureDefinition/alternate-canonical";
|
||||
public static final String EXT_SUPPRESSED = "http://hl7.org/fhir/StructureDefinition/elementdefinition-suppress";
|
||||
public static final String EXT_SUPPRESS_RESOURCE_TYPE = "http://hl7.org/fhir/tools/StructureDefinition/json-suppress-resourcetype";
|
||||
public static final String EXT_PROFILE_VIEW_HINT = "http://hl7.org/fhir/tools/StructureDefinition/view-hint";
|
||||
public static final String EXT_SNAPSHOT_BEHAVIOR = "http://hl7.org/fhir/tools/StructureDefinition/snapshot-behavior";
|
||||
|
||||
// specific extension helpers
|
||||
|
||||
@ -474,6 +476,7 @@ public class ToolingExtensions {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String readStringExtension(DomainResource c, String uri) {
|
||||
Extension ex = getExtension(c, uri);
|
||||
if (ex == null)
|
||||
@ -495,6 +498,30 @@ public class ToolingExtensions {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String readStringSubExtension(DomainResource c, String uri, String name) {
|
||||
Extension ex = getExtension(c, uri);
|
||||
if (ex == null)
|
||||
return null;
|
||||
ex = getExtension(ex, name);
|
||||
if (ex == null)
|
||||
return null;
|
||||
if ((ex.getValue() instanceof StringType))
|
||||
return ((StringType) ex.getValue()).getValue();
|
||||
if ((ex.getValue() instanceof UriType))
|
||||
return ((UriType) ex.getValue()).getValue();
|
||||
if (ex.getValue() instanceof CodeType)
|
||||
return ((CodeType) ex.getValue()).getValue();
|
||||
if (ex.getValue() instanceof IntegerType)
|
||||
return ((IntegerType) ex.getValue()).asStringValue();
|
||||
if (ex.getValue() instanceof Integer64Type)
|
||||
return ((Integer64Type) ex.getValue()).asStringValue();
|
||||
if (ex.getValue() instanceof DecimalType)
|
||||
return ((DecimalType) ex.getValue()).asStringValue();
|
||||
if ((ex.getValue() instanceof MarkdownType))
|
||||
return ((MarkdownType) ex.getValue()).getValue();
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static PrimitiveType<DataType> readPrimitiveExtension(DomainResource c, String uri) {
|
||||
Extension ex = getExtension(c, uri);
|
||||
|
@ -17,6 +17,7 @@ public class UserDataNames {
|
||||
public static final String SNAPSHOT_DERIVATION_POINTER = "derived.pointer";
|
||||
public static final String SNAPSHOT_IS_DERIVED = "derived.fact";
|
||||
public static final String SNAPSHOT_GENERATED_IN_SNAPSHOT = "profileutilities.snapshot.processed";
|
||||
public static final String SNAPSHOT_DERIVATION_DIFF = "profileutilities.snapshot.diffsource";
|
||||
public static final String SNAPSHOT_GENERATING = "profileutils.snapshot.generating";
|
||||
public static final String SNAPSHOT_GENERATED = "profileutils.snapshot.generated";
|
||||
public static final String SNAPSHOT_GENERATED_MESSAGES = "profileutils.snapshot.generated.messages";
|
||||
|
@ -1163,4 +1163,6 @@ public class I18nConstants {
|
||||
public static final String VS_EXP_IMPORT_FAIL_X = "VS_EXP_IMPORT_FAIL_X";
|
||||
public static final String VS_EXP_FILTER_UNK = "VS_EXP_FILTER_UNK";
|
||||
public static final String NO_VALID_DISPLAY_FOUND_NONE_FOR_LANG_ERR = "NO_VALID_DISPLAY_FOUND_NONE_FOR_LANG_ERR";
|
||||
public static final String CONCEPTMAP_VS_NOT_A_VS = "CONCEPTMAP_VS_NOT_A_VS";
|
||||
public static final String SD_DERIVATION_NO_CONCRETE = "SD_DERIVATION_NO_CONCRETE";
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import org.hl7.fhir.r5.model.CodeSystem;
|
||||
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
|
||||
import org.hl7.fhir.r5.model.Coding;
|
||||
import org.hl7.fhir.r5.model.Enumerations.CodeSystemContentMode;
|
||||
import org.hl7.fhir.r5.model.Resource;
|
||||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities;
|
||||
@ -144,8 +145,10 @@ public class ConceptMapValidator extends BaseValidator {
|
||||
}
|
||||
}
|
||||
}
|
||||
VSReference sourceScope = readVSReference(cm, "sourceScope", "source");
|
||||
VSReference targetScope = readVSReference(cm, "targetScope", "target");
|
||||
BooleanHolder bh = new BooleanHolder();
|
||||
VSReference sourceScope = readVSReference(errors, stack, bh, cm, "sourceScope", "source");
|
||||
VSReference targetScope = readVSReference(errors, stack, bh, cm, "targetScope", "target");
|
||||
ok = ok && bh.ok();
|
||||
|
||||
List<Element> groups = cm.getChildrenByName("group");
|
||||
int ci = 0;
|
||||
@ -191,7 +194,7 @@ public class ConceptMapValidator extends BaseValidator {
|
||||
}
|
||||
|
||||
|
||||
private VSReference readVSReference(Element cm, String... names) {
|
||||
private VSReference readVSReference(List<ValidationMessage> errors, NodeStack stack,BooleanHolder bok, Element cm, String... names) {
|
||||
for (String n : names) {
|
||||
if (cm.hasChild(n, false)) {
|
||||
Element e = cm.getNamedChild(n, false);
|
||||
@ -206,10 +209,32 @@ public class ConceptMapValidator extends BaseValidator {
|
||||
if (ref.contains("|")) {
|
||||
res.url = ref.substring(0, ref.indexOf("|"));
|
||||
res.version = ref.substring(ref.indexOf("|")+1);
|
||||
res.vs = context.findTxResource(ValueSet.class, res.url, res.version);
|
||||
Resource r = context.fetchResource(Resource.class, res.url, res.version);
|
||||
if (r != null) {
|
||||
if (r instanceof ValueSet) {
|
||||
res.vs = (ValueSet) r;
|
||||
} else {
|
||||
bok.fail();
|
||||
rule(errors, "2025-12-31", IssueType.INVALID, stack.getLiteralPath()+"."+n, false, I18nConstants.CONCEPTMAP_VS_NOT_A_VS, r.fhirType());
|
||||
}
|
||||
}
|
||||
if (res.vs == null) {
|
||||
res.vs = context.findTxResource(ValueSet.class, res.url, res.version);
|
||||
}
|
||||
} else {
|
||||
res.url = ref;
|
||||
res.vs = context.findTxResource(ValueSet.class, res.url);
|
||||
Resource r = context.fetchResource(Resource.class, res.url);
|
||||
if (r != null) {
|
||||
if (r instanceof ValueSet) {
|
||||
res.vs = (ValueSet) r;
|
||||
} else {
|
||||
bok.fail();
|
||||
rule(errors, "2025-12-31", IssueType.INVALID, stack.getLiteralPath()+"."+n, false, I18nConstants.CONCEPTMAP_VS_NOT_A_VS, r.fhirType());
|
||||
}
|
||||
}
|
||||
if (res.vs == null) {
|
||||
res.vs = context.findTxResource(ValueSet.class, res.url);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -162,6 +162,19 @@ public class StructureDefinitionValidator extends BaseValidator {
|
||||
warning(errors, "2024-09-17", IssueType.BUSINESSRULE, stack.getLiteralPath(), !base.getExperimental() || experimental, I18nConstants.SD_BASE_EXPERIMENTAL, sd.getBaseDefinition());
|
||||
}
|
||||
|
||||
String abstractV = src.getNamedChildValue("abstract");
|
||||
if ("true".equals(abstractV)) {
|
||||
String burl = src.getNamedChildValue("url");
|
||||
if (burl != null) {
|
||||
boolean bok = false;
|
||||
for (StructureDefinition sdb : context.fetchResourcesByType(StructureDefinition.class)) {
|
||||
if (burl.equals(sdb.getBaseDefinition())) {
|
||||
bok = true;
|
||||
}
|
||||
}
|
||||
warning(errors, "2024-12-31", IssueType.NOTFOUND, stack.getLiteralPath(), bok, I18nConstants.SD_DERIVATION_NO_CONCRETE, typeName);
|
||||
}
|
||||
}
|
||||
List<Element> differentials = src.getChildrenByName("differential");
|
||||
List<Element> snapshots = src.getChildrenByName("snapshot");
|
||||
boolean logical = "logical".equals(src.getNamedChildValue("kind", false));
|
||||
@ -684,33 +697,37 @@ public class StructureDefinitionValidator extends BaseValidator {
|
||||
boolean found = false;
|
||||
for (Element e : extensions) {
|
||||
if (ToolingExtensions.EXT_TYPE_PARAMETER.equals(e.getNamedChildValue("url"))) {
|
||||
String ename = e.getExtensionValue("name").primitiveValue();
|
||||
if (name.equals(ename)) {
|
||||
found = true;
|
||||
String etype = e.getExtensionValue("type").primitiveValue();
|
||||
for (Extension ex : sd.getExtensionsByUrl(ToolingExtensions.EXT_TYPE_PARAMETER)) {
|
||||
String tn = ex.getExtensionString("name");
|
||||
if (tn != null && tn.equals(etype)) {
|
||||
etype = ex.getExtensionString("type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
StructureDefinition esd = context.fetchTypeDefinition(etype);
|
||||
if (rule(errors, "2024-05-29", IssueType.BUSINESSRULE, stack.getLiteralPath(), esd != null, I18nConstants.SD_TYPE_PARAMETER_UNKNOWN, tc, etype)) {
|
||||
StructureDefinition t = esd;
|
||||
while (t != null && t != psd) {
|
||||
t = context.fetchResource(StructureDefinition.class, t.getBaseDefinition());
|
||||
}
|
||||
ok = rule(errors, "2024-05-29", IssueType.BUSINESSRULE, stack.getLiteralPath(), t != null, I18nConstants.SD_TYPE_PARAMETER_INVALID_REF, tc, etype, tsd.getVersionedUrl(), name, type) & ok;
|
||||
if (t != null) {
|
||||
if (!sd.getAbstract() && esd.getAbstract()) {
|
||||
warning(errors, "2024-05-29", IssueType.BUSINESSRULE, stack.getLiteralPath(), t != null, I18nConstants.SD_TYPE_PARAMETER_ABSTRACT_WARNING, tc, etype, tsd.getVersionedUrl(), name, type);
|
||||
if (!e.hasExtension("name")) {
|
||||
rule(errors, "2024-12-31", IssueType.BUSINESSRULE, stack.getLiteralPath(), false, I18nConstants.SD_TYPE_PARAMETER_UNKNOWN, tc, "no name");
|
||||
} else {
|
||||
String ename = e.getExtensionValue("name").primitiveValue();
|
||||
if (name.equals(ename)) {
|
||||
found = true;
|
||||
String etype = e.getExtensionValue("type").primitiveValue();
|
||||
for (Extension ex : sd.getExtensionsByUrl(ToolingExtensions.EXT_TYPE_PARAMETER)) {
|
||||
String tn = ex.getExtensionString("name");
|
||||
if (tn != null && tn.equals(etype)) {
|
||||
etype = ex.getExtensionString("type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
StructureDefinition esd = context.fetchTypeDefinition(etype);
|
||||
if (rule(errors, "2024-05-29", IssueType.BUSINESSRULE, stack.getLiteralPath(), esd != null, I18nConstants.SD_TYPE_PARAMETER_UNKNOWN, tc, etype)) {
|
||||
StructureDefinition t = esd;
|
||||
while (t != null && t != psd) {
|
||||
t = context.fetchResource(StructureDefinition.class, t.getBaseDefinition());
|
||||
}
|
||||
ok = rule(errors, "2024-05-29", IssueType.BUSINESSRULE, stack.getLiteralPath(), t != null, I18nConstants.SD_TYPE_PARAMETER_INVALID_REF, tc, etype, tsd.getVersionedUrl(), name, type) & ok;
|
||||
if (t != null) {
|
||||
if (!sd.getAbstract() && esd.getAbstract()) {
|
||||
warning(errors, "2024-05-29", IssueType.BUSINESSRULE, stack.getLiteralPath(), t != null, I18nConstants.SD_TYPE_PARAMETER_ABSTRACT_WARNING, tc, etype, tsd.getVersionedUrl(), name, type);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ok = rule(errors, "2024-05-29", IssueType.BUSINESSRULE, stack.getLiteralPath(), found, I18nConstants.SD_TYPE_PARAM_NOT_SPECIFIED, tc, tsd.getVersionedUrl(), name, path) && ok;
|
||||
|
Loading…
x
Reference in New Issue
Block a user