Skip to content

Commit 450556f

Browse files
authored
#550: Added a flatten parameter to support building derived model info (#551)
* #550: Added a flatten parameter to support building derived model info * Adding settings to better support IG-driven and derived model info creation * Fixes for derived model info support for QICore * Added USCore 8.0.0 profile set
1 parent f4f1a46 commit 450556f

11 files changed

Lines changed: 795 additions & 262 deletions

tooling/src/main/java/org/opencds/cqf/tooling/modelinfo/Atlas.java

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,7 @@
1616
import org.apache.commons.io.FileUtils;
1717
import org.apache.commons.io.filefilter.WildcardFileFilter;
1818
import org.hl7.fhir.instance.model.api.IBaseResource;
19-
import org.hl7.fhir.r4.model.Bundle;
20-
import org.hl7.fhir.r4.model.CapabilityStatement;
21-
import org.hl7.fhir.r4.model.CodeSystem;
22-
import org.hl7.fhir.r4.model.CompartmentDefinition;
23-
import org.hl7.fhir.r4.model.ConceptMap;
24-
import org.hl7.fhir.r4.model.ImplementationGuide;
25-
import org.hl7.fhir.r4.model.NamingSystem;
26-
import org.hl7.fhir.r4.model.OperationDefinition;
27-
import org.hl7.fhir.r4.model.Resource;
28-
import org.hl7.fhir.r4.model.ResourceType;
29-
import org.hl7.fhir.r4.model.SearchParameter;
30-
import org.hl7.fhir.r4.model.StructureDefinition;
31-
import org.hl7.fhir.r4.model.ValueSet;
19+
import org.hl7.fhir.r4.model.*;
3220
import org.opencds.cqf.tooling.utilities.CanonicalUtils;
3321

3422
import ca.uhn.fhir.context.FhirContext;
@@ -52,6 +40,7 @@ public Atlas() {
5240
valueSets = new HashMap<>();
5341
conceptMaps = new HashMap<>();
5442
namingSystems = new HashMap<>();
43+
parameters = new HashMap<>();
5544
}
5645

5746
private Map<String, Resource> resources;
@@ -117,6 +106,11 @@ public Map<String, NamingSystem> getNamingSystems() {
117106
return namingSystems;
118107
}
119108

109+
private Map<String, Parameters> parameters;
110+
public Map<String, Parameters> getParameters() {
111+
return parameters;
112+
}
113+
120114
public void loadPaths(String basePath, String resourcePaths) {
121115
String[] paths = resourcePaths.split(";");
122116
for (String path : paths) {
@@ -310,6 +304,16 @@ private void indexNamingSystem(NamingSystem namingSystem) {
310304
}
311305
}
312306

307+
private void indexParameters(Parameters parameters) {
308+
String id = parameters.getId();
309+
if (!this.parameters.containsKey(id)) {
310+
this.parameters.put(id, parameters);
311+
}
312+
else {
313+
logger.info("Duplicate Parameters with id {}", id);
314+
}
315+
}
316+
313317
private void indexResource(IBaseResource resource) {
314318
if (resource instanceof CapabilityStatement) {
315319
indexCapabilityStatement((CapabilityStatement)resource);
@@ -341,6 +345,9 @@ else if (resource instanceof ConceptMap) {
341345
else if (resource instanceof NamingSystem) {
342346
indexNamingSystem((NamingSystem)resource);
343347
}
348+
else if (resource instanceof Parameters) {
349+
indexParameters((Parameters)resource);
350+
}
344351
else {
345352
logger.info("Resource with id {} skipped", resource.getIdElement());
346353
}

tooling/src/main/java/org/opencds/cqf/tooling/modelinfo/ClassInfoBuilder.java

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,14 @@ private String getTail(String url) {
8282
}
8383
}
8484

85-
private String resolveModelName(String url) throws Exception {
85+
private String resolveModelName(String url) {
8686
// Strips off the identifier and type name
8787
String model = getHead(getHead(url));
8888
if (this.settings.urlToModel.containsKey(model)) {
8989
return this.settings.urlToModel.get(model);
9090
}
9191

92-
throw new Exception("Couldn't resolve model name for url: " + url);
92+
throw new IllegalArgumentException("Couldn't resolve model name for url: " + url);
9393
}
9494

9595
private String resolveTypeName(String url) throws Exception {
@@ -144,6 +144,12 @@ protected String getTypeName(StructureDefinition sd) {
144144
if (this.settings.modelPrefix != null && typeName.startsWith(this.settings.modelPrefix)) {
145145
typeName = typeName.substring(this.settings.modelPrefix.length());
146146
}
147+
else {
148+
String modelName = resolveModelName(sd.getUrl());
149+
if (modelName != null && typeName.startsWith(modelName)) {
150+
typeName = typeName.substring(modelName.length());
151+
}
152+
}
147153
typeName = mapTypeName(typeName);
148154
return typeName;
149155
}
@@ -556,7 +562,7 @@ private TypeSpecifier buildTypeSpecifier(String typeName) {
556562
return this.buildTypeSpecifier(this.getQualifier(typeName), this.unQualify(typeName));
557563
}
558564

559-
private String resolveMappedTypeName(String url) throws Exception {
565+
private String resolveMappedTypeName(String url) {
560566
if (url != null) {
561567
String modelName = resolveModelName(url);
562568
String typeName = getTypeNameFromUrl(url);
@@ -635,12 +641,22 @@ private String resolveMappedTypeName(String modelName, String typeName) {
635641

636642
private String resolveMappedTypeName(String modelName, TypeRefComponent typeRef) {
637643
if (typeRef.hasCode() && typeRef.getCode() != null) {
638-
return resolveMappedTypeName(modelName, typeRef.getCode());
644+
if (this.settings.flatten) {
645+
return resolveMappedTypeName(modelName, typeRef.getCode());
646+
}
647+
else {
648+
if (!typeRef.getCode().startsWith("http://hl7.org/fhirpath/")) {
649+
return resolveMappedTypeName("http://hl7.org/fhir/StructureDefinition/" + typeRef.getCode());
650+
}
651+
else {
652+
return resolveMappedTypeName(modelName, typeRef.getCode());
653+
}
654+
}
639655
}
640656

641657
Extension typeExtension = typeRef.getCodeElement().getExtensionByUrl("http://hl7.org/fhir/StructureDefinition/structuredefinition-xml-type");
642658
if (typeExtension != null) {
643-
return resolveMappedTypeName(modelName, typeExtension.getValue().toString());
659+
return resolveMappedTypeName(typeExtension.getValue().toString());
644660
}
645661

646662
throw new IllegalArgumentException("Could not determine mapping for null type code");
@@ -841,6 +857,8 @@ else if (hasRequiredBinding(ed, typeCode)) {
841857
String requiredBindingName = getRequiredBindingName(ed);
842858
if (requiredBindingName != null) {
843859
typeName = requiredBindingName;
860+
// NOTE: Always use FHIR as the model name here, since they are base specification defined
861+
modelName = "FHIR";
844862
requiredBindingName = getTypeName(modelName, typeName);
845863
if (!requiredBindingTypeNames.contains(requiredBindingName)) {
846864
requiredBindingTypeNames.add(requiredBindingName);
@@ -1151,7 +1169,7 @@ else if (slice.getElementTypeSpecifier() != null) {
11511169
// On return, index will be updated to the index of the next element to be
11521170
// processed
11531171
// This visit should not be used on the root element of a structure definition
1154-
private ClassInfoElement visitElementDefinition(String modelName, String pathRoot,
1172+
private ClassInfoElement visitElementDefinition(String modelName, String baseTypeName, String pathRoot,
11551173
List<ElementDefinition> eds, AtomicReference<Integer> index, SliceInfo sliceInfo, SliceList slices)
11561174
throws Exception {
11571175
ElementDefinition ed = eds.get(index.get());
@@ -1200,7 +1218,7 @@ else if (!this.settings.useCQLPrimitives) {
12001218
ElementDefinition e = eds.get(index.get());
12011219
if (isNextAContinuationOfElement(id, path, e)) {
12021220
SliceList elementSlices = new SliceList();
1203-
ClassInfoElement cie = this.visitElementDefinition(modelName, pathRoot, eds, index, sliceInfo, elementSlices);
1221+
ClassInfoElement cie = this.visitElementDefinition(modelName, baseTypeName, pathRoot, eds, index, sliceInfo, elementSlices);
12041222
if (cie != null && !(cie.getElementType() == null && cie.getElementTypeSpecifier() == null)) {
12051223
elements.add(cie);
12061224
}
@@ -1227,8 +1245,12 @@ else if (!this.settings.useCQLPrimitives) {
12271245
if (typeDefinition != null && (isBackboneElement(typeDefinition) || isElement(typeDefinition))) {
12281246
String typeName = this.capitalizePath(path);
12291247

1248+
String baseModelName = getQualifier(baseTypeName);
1249+
12301250
ClassInfo componentClassInfo = new ClassInfo().withNamespace(modelName).withName(typeName).withLabel(null)
1231-
.withBaseType(modelName + (isBackboneElement(typeDefinition) ? ".BackboneElement" : ".Element"))
1251+
.withBaseType(baseModelName.equals(modelName)
1252+
? (modelName + (isBackboneElement(typeDefinition) ? ".BackboneElement" : ".Element"))
1253+
: this.getTypeName(baseModelName, typeName))
12321254
.withRetrievable(false).withElement(elements).withPrimaryCodePath(null);
12331255

12341256
this.typeInfos.put(this.getTypeName(modelName, typeName), componentClassInfo);
@@ -1394,7 +1416,7 @@ else if (isSystemTypeName(getTypeName((NamedTypeSpecifier)typeSpecifier)) && sli
13941416
// This approach uses the base type to guide the walk, which requires navigating
13951417
// the derived profiles
13961418
private ClassInfo buildClassInfo(String modelName, StructureDefinition sd) throws Exception {
1397-
if (modelName == null) {
1419+
if (modelName == null || !this.settings.flatten) {
13981420
modelName = this.resolveModelName(sd.getUrl());
13991421
}
14001422
String typeName = getTypeName(sd);
@@ -1417,15 +1439,18 @@ private ClassInfo buildClassInfo(String modelName, StructureDefinition sd) throw
14171439
List<ClassInfoElement> elements = new ArrayList<>();
14181440
String path = sd.getType(); // Type is used to navigate the elements, regardless of the baseDefinition
14191441
String id = path; // Id starts with the Type
1420-
// TODO: Switch to differential here, but several of the primitive types declare "value" elements of type string when this happens? (positiveInt, markdown, among others)
14211442
List<ElementDefinition> eds = sd.getSnapshot().getElement();
14221443
SliceList elementSlices = null;
14231444

1445+
String baseDefinition = sd.getBaseDefinition();
1446+
String baseTypeName = (isStructureDefinitionResource(sd) && this.settings.flatten)
1447+
? resolveBaseTypeName(sd.getType()) : resolveTypeName(baseDefinition);
1448+
14241449
while (index.get() < eds.size()) {
14251450
ElementDefinition e = eds.get(index.get());
14261451
if (isNextAContinuationOfElement(id, path, e)) {
14271452
elementSlices = new SliceList();
1428-
ClassInfoElement cie = this.visitElementDefinition(modelName, path, eds, index, null, elementSlices);
1453+
ClassInfoElement cie = this.visitElementDefinition(modelName, baseTypeName, path, eds, index, null, elementSlices);
14291454
if (cie != null && !(cie.getElementType() == null && cie.getElementTypeSpecifier() == null)) {
14301455
elements.add(cie);
14311456
}
@@ -1441,12 +1466,8 @@ private ClassInfo buildClassInfo(String modelName, StructureDefinition sd) throw
14411466
}
14421467
}
14431468

1444-
String baseDefinition = sd.getBaseDefinition();
1445-
String baseTypeName = isStructureDefinitionResource(sd)
1446-
? resolveBaseTypeName(sd.getType()) : resolveTypeName(baseDefinition);
1447-
14481469
if (baseTypeName != null && !this.typeInfos.containsKey(baseTypeName)) {
1449-
StructureDefinition baseSd = this.structureDefinitions.get(unQualify(baseTypeName));
1470+
StructureDefinition baseSd = this.structureDefinitions.get(getTail(baseDefinition));
14501471
buildClassInfo(modelName, baseSd);
14511472
}
14521473

tooling/src/main/java/org/opencds/cqf/tooling/modelinfo/ClassInfoSettings.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ public class ClassInfoSettings {
1717
public boolean createExtensionElements = false;
1818
public boolean createReferenceElements = false;
1919

20+
public boolean flatten = false;
21+
2022
public Set<String> codeableTypes = new HashSet<String>();
2123
public Map<String, String> primitiveTypeMappings = new HashMap<String, String>();
2224
public Map<String, String> cqlTypeMappings = new HashMap<String, String>();

tooling/src/main/java/org/opencds/cqf/tooling/modelinfo/ModelInfoBuilder.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,12 @@ protected ModelInfo innerBuild() {
3131
.sorted(Comparator.comparing(ClassInfo::getName))
3232
.collect(Collectors.toList());
3333

34-
ModelInfo mi = new ModelInfo().withRequiredModelInfo(new ModelSpecifier().withName("System").withVersion("1.0.0"))
35-
.withTypeInfo(modelTypeInfos)
34+
ModelInfo mi = new ModelInfo()
35+
.withRequiredModelInfo(new ModelSpecifier().withName("System").withVersion("1.0.0"))
36+
.withTypeInfo(modelTypeInfos.stream().filter(
37+
x -> x instanceof ClassInfo && ((ClassInfo)x).getNamespace() != null
38+
&& ((ClassInfo)x).getNamespace().equals(this.settings.name)
39+
).collect(Collectors.toList()))
3640
.withConversionInfo(this.settings.conversionInfos)
3741
.withName(this.settings.name)
3842
.withVersion(this.settings.version)

0 commit comments

Comments
 (0)