Improvements to profile comparison

This commit is contained in:
Grahame Grieve 2022-06-24 11:40:42 +02:00
parent 45efd0afaf
commit 636c651d76
5 changed files with 67 additions and 19 deletions

View File

@ -9,6 +9,8 @@ import java.util.Map;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.comparison.ProfileComparer.ProfileComparison;
import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.BackboneElement;
@ -86,7 +88,7 @@ public class CapabilityStatementComparer extends CanonicalResourceComparer {
super(session);
}
public CapabilityStatementComparison compare(CapabilityStatement left, CapabilityStatement right) {
public CapabilityStatementComparison compare(CapabilityStatement left, CapabilityStatement right) throws DefinitionException, FHIRFormatError, IOException {
if (left == null)
throw new DefinitionException("No CapabilityStatement provided (left)");
if (right == null)
@ -130,7 +132,7 @@ public class CapabilityStatementComparer extends CanonicalResourceComparer {
return res;
}
private void compareRests(List<CapabilityStatementRestComponent> left, List<CapabilityStatementRestComponent> right, StructuralMatch<Element> combined, List<CapabilityStatementRestComponent> union, List<CapabilityStatementRestComponent> intersection, CapabilityStatement csU, CapabilityStatement csI, CapabilityStatementComparison res, String path) {
private void compareRests(List<CapabilityStatementRestComponent> left, List<CapabilityStatementRestComponent> right, StructuralMatch<Element> combined, List<CapabilityStatementRestComponent> union, List<CapabilityStatementRestComponent> intersection, CapabilityStatement csU, CapabilityStatement csI, CapabilityStatementComparison res, String path) throws DefinitionException, FHIRFormatError, IOException {
List<CapabilityStatementRestComponent> matchR = new ArrayList<>();
for (CapabilityStatementRestComponent l : left) {
CapabilityStatementRestComponent r = findInList(right, l);
@ -203,10 +205,12 @@ public class CapabilityStatementComparer extends CanonicalResourceComparer {
combined.getChildren().add(sm);
}
}
for (CodeableConcept r : right.getService()) {
if (!matchR.contains(r)) {
union.getService().add(r);
combined.getChildren().add(new StructuralMatch<Element>(vmI(IssueSeverity.INFORMATION, "Added this concept", path), r));
if (right != null) {
for (CodeableConcept r : right.getService()) {
if (!matchR.contains(r)) {
union.getService().add(r);
combined.getChildren().add(new StructuralMatch<Element>(vmI(IssueSeverity.INFORMATION, "Added this concept", path), r));
}
}
}
}
@ -384,7 +388,7 @@ public class CapabilityStatementComparer extends CanonicalResourceComparer {
tgt.removeAll(toRemove);
}
private void compareRestResources(CapabilityStatementRestComponent left, CapabilityStatementRestComponent right, StructuralMatch<Element> combined, CapabilityStatementRestComponent union, CapabilityStatementRestComponent intersection, CapabilityStatement csU, CapabilityStatement csI, CapabilityStatementComparison res, String path) {
private void compareRestResources(CapabilityStatementRestComponent left, CapabilityStatementRestComponent right, StructuralMatch<Element> combined, CapabilityStatementRestComponent union, CapabilityStatementRestComponent intersection, CapabilityStatement csU, CapabilityStatement csI, CapabilityStatementComparison res, String path) throws DefinitionException, FHIRFormatError, IOException {
List<CapabilityStatementRestResourceComponent> matchR = new ArrayList<>();
for (CapabilityStatementRestResourceComponent l : left.getResource()) {
CapabilityStatementRestResourceComponent r = findInList(right.getResource(), l);
@ -410,7 +414,7 @@ public class CapabilityStatementComparer extends CanonicalResourceComparer {
}
}
private void compareRestResource(StructuralMatch<Element> sm, CapabilityStatementRestResourceComponent l, CapabilityStatementRestResourceComponent r, String path, CapabilityStatementComparison res, CapabilityStatementRestResourceComponent union, CapabilityStatementRestResourceComponent intersection) {
private void compareRestResource(StructuralMatch<Element> sm, CapabilityStatementRestResourceComponent l, CapabilityStatementRestResourceComponent r, String path, CapabilityStatementComparison res, CapabilityStatementRestResourceComponent union, CapabilityStatementRestResourceComponent intersection) throws DefinitionException, FHIRFormatError, IOException {
compareProfiles(path, sm, l.getProfileElement(), r.getProfileElement(), res, union, intersection);
// todo: supported profiles
compareStrings(path, sm.getMessages(), l.getDocumentation(), r.getDocumentation(), "documentation", IssueSeverity.INFORMATION, res);
@ -430,7 +434,7 @@ public class CapabilityStatementComparer extends CanonicalResourceComparer {
compareOperations(sm, l.getOperation(), r.getOperation(), path, res, union.getOperation(), intersection.getOperation());
}
private void compareProfiles(String path, StructuralMatch<Element> combined, CanonicalType left, CanonicalType right, CapabilityStatementComparison res, CapabilityStatementRestResourceComponent union, CapabilityStatementRestResourceComponent intersection) {
private void compareProfiles(String path, StructuralMatch<Element> combined, CanonicalType left, CanonicalType right, CapabilityStatementComparison res, CapabilityStatementRestResourceComponent union, CapabilityStatementRestResourceComponent intersection) throws DefinitionException, FHIRFormatError, IOException {
if (!left.hasValue() && !right.hasValue()) {
// nothing in this case
} else if (!left.hasValue()) {
@ -466,7 +470,9 @@ public class CapabilityStatementComparer extends CanonicalResourceComparer {
combined.getChildren().add(new StructuralMatch<Element>(left, right, vmI(IssueSeverity.WARNING, "Changed this profile to a narrower one", path)).setName("profile"));
} else {
combined.getChildren().add(new StructuralMatch<Element>(left, right, vmI(IssueSeverity.WARNING, "Different", path)).setName("profile"));
throw new Error("Not done yet");
ProfileComparison pc = (ProfileComparison) session.compare(sdLeft, sdRight);
intersection.setProfile(pc.getIntersection().getUrl());
union.setProfile(pc.getUnion().getUrl());
}
}
}

View File

@ -14,6 +14,7 @@ import java.util.Set;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.PathEngineException;
import org.hl7.fhir.r5.comparison.CapabilityStatementComparer.CapabilityStatementComparison;
import org.hl7.fhir.r5.comparison.CodeSystemComparer.CodeSystemComparison;
import org.hl7.fhir.r5.comparison.ProfileComparer.ProfileComparison;
import org.hl7.fhir.r5.comparison.ResourceComparer.PlaceHolderComparison;
@ -133,6 +134,8 @@ public class ComparisonRenderer implements IEvaluationContext {
renderValueSet(id, (ValueSetComparison) comp);
} else if (comp instanceof CodeSystemComparison) {
renderCodeSystem(id, (CodeSystemComparison) comp);
} else if (comp instanceof CapabilityStatementComparison) {
renderCapabilityStatement(id, (CapabilityStatementComparison) comp);
} else if (comp instanceof PlaceHolderComparison) {
renderPlaceHolder(id, (PlaceHolderComparison) comp);
}
@ -211,6 +214,25 @@ public class ComparisonRenderer implements IEvaluationContext {
new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(folder, comp.getId() + "-union.json")), comp.getUnion());
new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(folder, comp.getId() + "-intersection.json")), comp.getIntersection());
}
private void renderCapabilityStatement(String id, CapabilityStatementComparison comp) throws IOException {
String template = templates.get("CapabilityStatement");
Map<String, Base> vars = new HashMap<>();
CapabilityStatementComparer cs = new CapabilityStatementComparer(session);
vars.put("left", new StringType(comp.getLeft().present()));
vars.put("right", new StringType(comp.getRight().present()));
vars.put("leftId", new StringType(comp.getLeft().getId()));
vars.put("rightId", new StringType(comp.getRight().getId()));
vars.put("leftUrl", new StringType(comp.getLeft().getUrl()));
vars.put("rightUrl", new StringType(comp.getRight().getUrl()));
vars.put("errors", new StringType(new XhtmlComposer(true).compose(cs.renderErrors(comp))));
vars.put("metadata", new StringType(new XhtmlComposer(true).compose(cs.renderMetadata(comp, "", ""))));
vars.put("statement", new StringType(new XhtmlComposer(true).compose(cs.renderStatements(comp, "", ""))));
String cnt = processTemplate(template, "CapabilityStatement", vars);
TextFile.stringToFile(cnt, file(comp.getId()+".html"));
new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(folder, comp.getId() + "-union.json")), comp.getUnion());
new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(folder, comp.getId() + "-intersection.json")), comp.getIntersection());
}
private String processTemplate(String template, String name, Map<String, Base> vars) {
LiquidEngine engine = new LiquidEngine(contextRight, this);

View File

@ -8,6 +8,7 @@ import java.util.UUID;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.comparison.CapabilityStatementComparer.CapabilityStatementComparison;
import org.hl7.fhir.r5.comparison.CodeSystemComparer.CodeSystemComparison;
import org.hl7.fhir.r5.comparison.ProfileComparer.ProfileComparison;
import org.hl7.fhir.r5.comparison.ResourceComparer.ResourceComparison;
@ -16,6 +17,7 @@ import org.hl7.fhir.r5.conformance.ProfileUtilities;
import org.hl7.fhir.r5.conformance.ProfileUtilities.ProfileKnowledgeProvider;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.CapabilityStatement;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.StructureDefinition;
@ -24,6 +26,7 @@ import org.hl7.fhir.utilities.Utilities;
public class ComparisonSession {
private Map<String, ResourceComparison> compares = new HashMap<>();
private IWorkerContext contextLeft;
private IWorkerContext contextRight;
@ -42,7 +45,7 @@ public class ComparisonSession {
this.title = title;
this.pkpLeft = pkpLeft;
this.pkpRight = pkpRight;
// debug = true;
debug = false;
}
public IWorkerContext getContextLeft() {
@ -94,10 +97,18 @@ public class ComparisonSession {
ProfileComparison csc = cs.compare((StructureDefinition) left, (StructureDefinition) right);
compares.put(key, csc);
return csc;
} else if (left instanceof CapabilityStatement && right instanceof CapabilityStatement) {
CapabilityStatementComparer cs = new CapabilityStatementComparer(this);
CapabilityStatementComparison csc = cs.compare((CapabilityStatement) left, (CapabilityStatement) right);
compares.put(key, csc);
return csc;
} else {
throw new FHIRException("Unable to compare resources of type "+left.fhirType()+" and "+right.fhirType());
}
} catch (Throwable e) {
if (debug) {
e.printStackTrace();
}
ResourceComparer.PlaceHolderComparison csc = new ResourceComparer.PlaceHolderComparison(left, right, e);
compares.put(key, csc);
return csc;

View File

@ -19,10 +19,12 @@ import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.DataType;
import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.ElementDefinition.AggregationMode;
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent;
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionConstraintComponent;
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionMappingComponent;
import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent;
import org.hl7.fhir.r5.model.Enumeration;
import org.hl7.fhir.r5.model.Enumerations.BindingStrength;
import org.hl7.fhir.r5.model.IntegerType;
import org.hl7.fhir.r5.model.PrimitiveType;
@ -539,10 +541,13 @@ public class ProfileComparer extends CanonicalResourceComparer {
boolean pfound = false;
boolean tfound = false;
nw = nw.copy();
if (nw.hasAggregation())
throw new DefinitionException("Aggregation not supported: "+path);
for (TypeRefComponent ex : results) {
if (Utilities.equals(ex.getWorkingCode(), nw.getWorkingCode())) {
for (Enumeration<AggregationMode> a : nw.getAggregation()) {
if (!ex.hasAggregation(a.getValue())) {
ex.addAggregation(a.getValue());
}
}
if (!ex.hasProfile() && !nw.hasProfile())
pfound = true;
else if (!ex.hasProfile()) {
@ -635,14 +640,10 @@ public class ProfileComparer extends CanonicalResourceComparer {
private Collection<? extends TypeRefComponent> intersectTypes(ProfileComparison comp, StructuralMatch<ElementDefinitionNode> res, ElementDefinition ed, String path, List<TypeRefComponent> left, List<TypeRefComponent> right) throws DefinitionException, IOException, FHIRFormatError {
List<TypeRefComponent> result = new ArrayList<TypeRefComponent>();
for (TypeRefComponent l : left) {
if (l.hasAggregation())
throw new DefinitionException("Aggregation not supported: "+path);
boolean pfound = false;
boolean tfound = false;
TypeRefComponent c = l.copy();
for (TypeRefComponent r : right) {
if (r.hasAggregation())
throw new DefinitionException("Aggregation not supported: "+path);
if (!l.hasProfile() && !r.hasProfile()) {
pfound = true;
} else if (!r.hasProfile()) {
@ -697,9 +698,17 @@ public class ProfileComparer extends CanonicalResourceComparer {
}
}
}
if (pfound && tfound) {
for (Enumeration<AggregationMode> a : l.getAggregation()) {
if (!r.hasAggregation(a.getValue())) {
c.getAggregation().removeIf(n -> n.getValue() == a.getValue());
}
}
}
}
if (pfound && tfound)
if (pfound && tfound) {
result.add(c);
}
}
return result;
}

View File

@ -193,7 +193,7 @@ public class ValueSetComparer extends CanonicalResourceComparer {
if (matchCount == 1 && sourceCount == 1) {
for (ConceptSetComponent t : matches) {
if (t.getSystem().equals(item.getSystem())) {
if (t.getSystem() != null && t.getSystem().equals(item.getSystem())) {
return t;
}
}