From 636c651d76ed4c4438626faf33b16dcc822281f0 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Fri, 24 Jun 2022 11:40:42 +0200 Subject: [PATCH] Improvements to profile comparison --- .../CapabilityStatementComparer.java | 26 ++++++++++++------- .../r5/comparison/ComparisonRenderer.java | 22 ++++++++++++++++ .../fhir/r5/comparison/ComparisonSession.java | 13 +++++++++- .../fhir/r5/comparison/ProfileComparer.java | 23 +++++++++++----- .../fhir/r5/comparison/ValueSetComparer.java | 2 +- 5 files changed, 67 insertions(+), 19 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/CapabilityStatementComparer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/CapabilityStatementComparer.java index 0f82da2ce..bc8044a78 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/CapabilityStatementComparer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/CapabilityStatementComparer.java @@ -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 left, List right, StructuralMatch combined, List union, List intersection, CapabilityStatement csU, CapabilityStatement csI, CapabilityStatementComparison res, String path) { + private void compareRests(List left, List right, StructuralMatch combined, List union, List intersection, CapabilityStatement csU, CapabilityStatement csI, CapabilityStatementComparison res, String path) throws DefinitionException, FHIRFormatError, IOException { List 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(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(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 combined, CapabilityStatementRestComponent union, CapabilityStatementRestComponent intersection, CapabilityStatement csU, CapabilityStatement csI, CapabilityStatementComparison res, String path) { + private void compareRestResources(CapabilityStatementRestComponent left, CapabilityStatementRestComponent right, StructuralMatch combined, CapabilityStatementRestComponent union, CapabilityStatementRestComponent intersection, CapabilityStatement csU, CapabilityStatement csI, CapabilityStatementComparison res, String path) throws DefinitionException, FHIRFormatError, IOException { List 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 sm, CapabilityStatementRestResourceComponent l, CapabilityStatementRestResourceComponent r, String path, CapabilityStatementComparison res, CapabilityStatementRestResourceComponent union, CapabilityStatementRestResourceComponent intersection) { + private void compareRestResource(StructuralMatch 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 combined, CanonicalType left, CanonicalType right, CapabilityStatementComparison res, CapabilityStatementRestResourceComponent union, CapabilityStatementRestResourceComponent intersection) { + private void compareProfiles(String path, StructuralMatch 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(left, right, vmI(IssueSeverity.WARNING, "Changed this profile to a narrower one", path)).setName("profile")); } else { combined.getChildren().add(new StructuralMatch(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()); } } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ComparisonRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ComparisonRenderer.java index 6a8f164e8..2e69deade 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ComparisonRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ComparisonRenderer.java @@ -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 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 vars) { LiquidEngine engine = new LiquidEngine(contextRight, this); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ComparisonSession.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ComparisonSession.java index 5462fd1c2..b718482c7 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ComparisonSession.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ComparisonSession.java @@ -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 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; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ProfileComparer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ProfileComparer.java index 2ee855c24..990bb72b5 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ProfileComparer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ProfileComparer.java @@ -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 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 intersectTypes(ProfileComparison comp, StructuralMatch res, ElementDefinition ed, String path, List left, List right) throws DefinitionException, IOException, FHIRFormatError { List result = new ArrayList(); 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 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; } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ValueSetComparer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ValueSetComparer.java index 1d0543b84..d4e6b33d4 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ValueSetComparer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ValueSetComparer.java @@ -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; } }