diff --git a/.gitignore b/.gitignore index 01b1acf66..9e58ea6a0 100644 --- a/.gitignore +++ b/.gitignore @@ -304,3 +304,4 @@ local.properties /org.hl7.fhir.r5/src/test/resources/snapshot-generation/logical2-actual.xml /org.hl7.fhir.r5.new /org.hl7.fhir.r5.newc +/org.hl7.fhir.r4b.new diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/ExamplesPackageBuilder.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/ExamplesPackageBuilder.java new file mode 100644 index 000000000..13cc57fc0 --- /dev/null +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/ExamplesPackageBuilder.java @@ -0,0 +1,74 @@ +package org.hl7.fhir.convertors.misc; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.HashSet; +import java.util.Set; + +import org.hl7.fhir.convertors.factory.VersionConvertorFactory_30_50; +import org.hl7.fhir.convertors.factory.VersionConvertorFactory_40_50; +import org.hl7.fhir.exceptions.FHIRFormatError; +import org.hl7.fhir.r4b.formats.JsonParser; +import org.hl7.fhir.r4b.model.Bundle; +import org.hl7.fhir.r4b.model.Bundle.BundleEntryComponent; +import org.hl7.fhir.utilities.TextFile; +import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.utilities.json.JsonTrackingParser; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; + +import org.hl7.fhir.r4b.model.SearchParameter; +import org.hl7.fhir.r4b.utils.NPMPackageGenerator; +import org.hl7.fhir.r4b.utils.NPMPackageGenerator.Category; + +public class ExamplesPackageBuilder { + + public static void main(String[] args) throws FHIRFormatError, FileNotFoundException, IOException { + new ExamplesPackageBuilder().process(args[0]); + + } + + private void process(String source) throws FHIRFormatError, FileNotFoundException, IOException { + Set set = new HashSet<>(); + for (File f : new File(source).listFiles()) { + if (f.getName().endsWith(".json")) { + JsonObject obj = JsonTrackingParser.parseJson(new FileInputStream(f)); + if (obj.has("resourceType") && obj.has("id")) { + String type = obj.get("resourceType").getAsString(); + String id = obj.get("id").getAsString(); + byte[] content = TextFile.fileToBytes(f); + if (type.equals("ConceptMap")) { + System.out.println("convert "+f.getName()); + content = r5ToR4B(content); + TextFile.bytesToFile(content, f); + } +// TextFile.bytesToFile(content, Utilities.path(dest2, type+"-"+id+".json")); +// if (!set.contains(type+"/"+id)) { +// set.add(type+"/"+id); +// pck.addFile(Category.RESOURCE, type+"-"+id+".json", content); +// } + } + } + } +// pck.finish(); +// + } + + private byte[] r5ToR4B(byte[] content) throws FHIRFormatError, IOException { + try { + org.hl7.fhir.r5.model.Resource r5 = new org.hl7.fhir.r5.formats.JsonParser().parse(content); + org.hl7.fhir.r4.model.Resource r4 = VersionConvertorFactory_40_50.convertResource(r5); + return new org.hl7.fhir.r4.formats.JsonParser().composeBytes(r4); + } catch (Exception e) { + System.out.println(" .. failed: "+e.getMessage()); + return content; + } + } + +} diff --git a/org.hl7.fhir.core.generator/src/org/hl7/fhir/core/generator/engine/DefinitionsLoaderR4B.java b/org.hl7.fhir.core.generator/src/org/hl7/fhir/core/generator/engine/DefinitionsLoaderR4B.java new file mode 100644 index 000000000..cecb92e77 --- /dev/null +++ b/org.hl7.fhir.core.generator/src/org/hl7/fhir/core/generator/engine/DefinitionsLoaderR4B.java @@ -0,0 +1,87 @@ +package org.hl7.fhir.core.generator.engine; + +import java.io.IOException; + +import org.hl7.fhir.convertors.factory.VersionConvertorFactory_40_50; +import org.hl7.fhir.exceptions.FHIRFormatError; +import org.hl7.fhir.r4.formats.JsonParser; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; +import org.hl7.fhir.r5.model.CapabilityStatement; +import org.hl7.fhir.r5.model.CodeSystem; +import org.hl7.fhir.r5.model.CompartmentDefinition; +import org.hl7.fhir.r5.model.ConceptMap; +import org.hl7.fhir.r5.model.OperationDefinition; +import org.hl7.fhir.r5.model.Resource; +import org.hl7.fhir.r5.model.SearchParameter; +import org.hl7.fhir.r5.model.StructureDefinition; +import org.hl7.fhir.r5.model.ValueSet; +import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.utilities.npm.NpmPackage; +import org.hl7.fhir.utilities.npm.ToolsVersion; + +public class DefinitionsLoaderR4B { + + public static Definitions load(NpmPackage npm) throws IOException { + Definitions res = new Definitions(); + + for (String t : npm.listResources("CodeSystem")) { + res.getCodeSystems().see((CodeSystem) load(npm, t), null); + } + for (String t : npm.listResources("ValueSet")) { + res.getValuesets().see((ValueSet) load(npm, t), null); + } + for (String t : npm.listResources("ConceptMap")) { + res.getConceptMaps().see((ConceptMap) load(npm, t), null); + } + for (String t : npm.listResources("CapabilityStatement")) { + res.getStatements().see((CapabilityStatement) load(npm, t), null); + } + for (String t : npm.listResources("StructureDefinition")) { + res.getStructures().see((StructureDefinition) load(npm, t), null); + } + for (String t : npm.listResources("OperationDefinition")) { + res.getOperations().see((OperationDefinition) load(npm, t), null); + } + for (String t : npm.listResources("SearchParameter")) { + res.getSearchParams().see((SearchParameter) load(npm, t), null); + } + for (String t : npm.listResources("CompartmentDefinition")) { + res.getCompartments().see((CompartmentDefinition) load(npm, t), null); + } +// Bundle bnd = (Bundle) load(npm, "Bundle-searchParams.json"); +// if (bnd != null) { +// for (BundleEntryComponent be : bnd.getEntry()) { +// Resource r = be.getResource(); +// if (r instanceof CodeSystem) { +// res.getCodeSystems().see((CodeSystem) r, null); +// } else if (r instanceof ValueSet) { +// res.getValuesets().see((ValueSet) r, null); +// } else if (r instanceof ConceptMap) { +// res.getConceptMaps().see((ConceptMap) r, null); +// } else if (r instanceof CapabilityStatement) { +// res.getStatements().see((CapabilityStatement) r, null); +// } else if (r instanceof StructureDefinition) { +// res.getStructures().see((StructureDefinition) r, null); +// } else if (r instanceof OperationDefinition) { +// res.getOperations().see((OperationDefinition) r, null); +// } else if (r instanceof SearchParameter) { +// res.getSearchParams().see((SearchParameter) r, null); +// } else if (r instanceof CompartmentDefinition) { +// res.getCompartments().see((CompartmentDefinition) r, null); +// } +// } +// } + return res; + } + + public static Resource load(NpmPackage npm, String t) { + try { + return VersionConvertorFactory_40_50.convertResource(new JsonParser().parse(npm.loadResource(t))); + } catch (Exception e) { + System.out.println("Error reading "+t+": "+e.getMessage()); + e.printStackTrace(); + return null; + } + } +} \ No newline at end of file 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 338487903..d6a76105a 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 @@ -45,14 +45,14 @@ public class ProfileComparer extends CanonicalResourceComparer { public class ProfileComparison extends CanonicalResourceComparison { - private StructuralMatch combined; + private StructuralMatch combined; public ProfileComparison(StructureDefinition left, StructureDefinition right) { super(left, right); - combined = new StructuralMatch(); // base + combined = new StructuralMatch(); // base } - public StructuralMatch getCombined() { + public StructuralMatch getCombined() { return combined; } @@ -79,7 +79,21 @@ public class ProfileComparer extends CanonicalResourceComparer { } - + private class ElementDefinitionNode { + private ElementDefinition def; + private StructureDefinition src; + private ElementDefinitionNode(StructureDefinition src, ElementDefinition def) { + super(); + this.src = src; + this.def = def; + } + public ElementDefinition getDef() { + return def; + } + public StructureDefinition getSrc() { + return src; + } + } private ProfileUtilities utilsLeft; private ProfileUtilities utilsRight; @@ -127,7 +141,7 @@ public class ProfileComparer extends CanonicalResourceComparer { if (left.getType().equals(right.getType())) { DefinitionNavigator ln = new DefinitionNavigator(session.getContextLeft(), left); DefinitionNavigator rn = new DefinitionNavigator(session.getContextRight(), right); - StructuralMatch sm = new StructuralMatch(ln.current(), rn.current()); + StructuralMatch sm = new StructuralMatch(new ElementDefinitionNode(left, ln.current()), new ElementDefinitionNode(right, rn.current())); compareElements(res, sm, ln.path(), null, ln, rn); res.combined = sm; } @@ -147,7 +161,7 @@ public class ProfileComparer extends CanonicalResourceComparer { throw new DefinitionException("StructureDefinition snapshot is empty ("+name+": "+sd.getName()+")"); } - private void compareElements(ProfileComparison comp, StructuralMatch res, String path, String sliceName, DefinitionNavigator left, DefinitionNavigator right) throws DefinitionException, FHIRFormatError, IOException { + private void compareElements(ProfileComparison comp, StructuralMatch res, String path, String sliceName, DefinitionNavigator left, DefinitionNavigator right) throws DefinitionException, FHIRFormatError, IOException { assert(path != null); assert(left != null); assert(right != null); @@ -190,7 +204,7 @@ public class ProfileComparer extends CanonicalResourceComparer { subset.setExample(left.current().hasExample() ? left.current().getExample() : right.current().getExample()); if (left.current().getMustSupport() != right.current().getMustSupport()) { - vm(IssueSeverity.ERROR, "Elements differ in definition for mustSupport:\r\n \""+left.current().getMustSupport()+"\"\r\n \""+right.current().getMustSupport()+"\"", path, comp.getMessages(), res.getMessages()); + vm(IssueSeverity.WARNING, "Elements differ in definition for mustSupport:\r\n \""+left.current().getMustSupport()+"\"\r\n \""+right.current().getMustSupport()+"\"", path, comp.getMessages(), res.getMessages()); } subset.setMustSupport(left.current().getMustSupport() || right.current().getMustSupport()); @@ -198,11 +212,16 @@ public class ProfileComparer extends CanonicalResourceComparer { // compare and intersect - superset.setMin(unionMin(left.current().getMin(), right.current().getMin())); - superset.setMax(unionMax(left.current().getMax(), right.current().getMax())); - subset.setMin(intersectMin(left.current().getMin(), right.current().getMin())); - subset.setMax(intersectMax(left.current().getMax(), right.current().getMax())); - rule(comp, res, subset.getMax().equals("*") || Integer.parseInt(subset.getMax()) >= subset.getMin(), path, "Cardinality Mismatch: "+card(left)+"/"+card(right)); + int leftMin = left.current().getMin(); + int rightMin = right.current().getMin(); + int leftMax = "*".equals(left.current().getMax()) ? Integer.MAX_VALUE : Integer.parseInt(left.current().getMax()); + int rightMax = "*".equals(right.current().getMax()) ? Integer.MAX_VALUE : Integer.parseInt(right.current().getMax()); + + checkMinMax(comp, res, path, leftMin, rightMin, leftMax, rightMax); + superset.setMin(unionMin(leftMin, rightMin)); + superset.setMax(unionMax(leftMax, rightMax, left.current().getMax(), right.current().getMax())); + subset.setMin(intersectMin(leftMin, rightMin)); + subset.setMax(intersectMax(leftMax, rightMax, left.current().getMax(), right.current().getMax())); superset.getType().addAll(unionTypes(comp, res, path, left.current().getType(), right.current().getType())); subset.getType().addAll(intersectTypes(comp, res, subset, path, left.current().getType(), right.current().getType())); @@ -283,7 +302,8 @@ public class ProfileComparer extends CanonicalResourceComparer { // return null; } - private void compareChildren(ProfileComparison comp, StructuralMatch res, String path, DefinitionNavigator left, DefinitionNavigator right) throws DefinitionException, IOException, FHIRFormatError { + + private void compareChildren(ProfileComparison comp, StructuralMatch res, String path, DefinitionNavigator left, DefinitionNavigator right) throws DefinitionException, IOException, FHIRFormatError { List lc = left.children(); List rc = right.children(); // it's possible that one of these profiles walks into a data type and the other doesn't @@ -299,10 +319,10 @@ public class ProfileComparer extends CanonicalResourceComparer { DefinitionNavigator r = findInList(rc, l); if (r == null) { comp.getUnion().getSnapshot().getElement().add(l.current().copy()); - res.getChildren().add(new StructuralMatch(l.current(), vmI(IssueSeverity.INFORMATION, "Removed this element", path))); + res.getChildren().add(new StructuralMatch(new ElementDefinitionNode(l.getStructure(), l.current()), vmI(IssueSeverity.INFORMATION, "Removed this element", path))); } else { matchR.add(r); - StructuralMatch sm = new StructuralMatch(l.current(), r.current()); + StructuralMatch sm = new StructuralMatch(new ElementDefinitionNode(l.getStructure(), l.current()), new ElementDefinitionNode(r.getStructure(), r.current())); res.getChildren().add(sm); compareElements(comp, sm, l.path(), null, l, r); } @@ -310,7 +330,7 @@ public class ProfileComparer extends CanonicalResourceComparer { for (DefinitionNavigator r : rc) { if (!matchR.contains(r)) { comp.getUnion().getSnapshot().getElement().add(r.current().copy()); - res.getChildren().add(new StructuralMatch(vmI(IssueSeverity.INFORMATION, "Added this element", path), r.current())); + res.getChildren().add(new StructuralMatch(vmI(IssueSeverity.INFORMATION, "Added this element", path), new ElementDefinitionNode(r.getStructure(), r.current()))); } } } @@ -324,7 +344,7 @@ public class ProfileComparer extends CanonicalResourceComparer { return null; } - private void ruleEqual(ProfileComparison comp, StructuralMatch res, DataType vLeft, DataType vRight, String name, String path) throws IOException { + private void ruleEqual(ProfileComparison comp, StructuralMatch res, DataType vLeft, DataType vRight, String name, String path) throws IOException { if (vLeft == null && vRight == null) { // nothing } else if (vLeft == null) { @@ -356,14 +376,14 @@ public class ProfileComparer extends CanonicalResourceComparer { return s; } - private boolean rule(ProfileComparison comp, StructuralMatch res, boolean test, String path, String message) { + private boolean rule(ProfileComparison comp, StructuralMatch res, boolean test, String path, String message) { if (!test) { vm(IssueSeverity.ERROR, message, path, comp.getMessages(), res.getMessages()); } return test; } - private String mergeText(ProfileComparison comp, StructuralMatch res, String path, String name, String left, String right, boolean isError) { + private String mergeText(ProfileComparison comp, StructuralMatch res, String path, String name, String left, String right, boolean isError) { if (left == null && right == null) return null; if (left == null) @@ -429,6 +449,36 @@ public class ProfileComparer extends CanonicalResourceComparer { return right; } + private void checkMinMax(ProfileComparison comp, StructuralMatch res, String path, int leftMin, int rightMin, int leftMax, int rightMax) { + if (leftMin != rightMin) { + if (leftMin == 0) { + vm(IssueSeverity.INFORMATION, "Element minimum cardinalities differ:\r\n \""+leftMin+"\"\r\n vs \""+rightMin+"\"", path, comp.getMessages(), res.getMessages()); + } else if (rightMin == 0) { + vm(IssueSeverity.INFORMATION, "Element minimum cardinalities differ:\r\n \""+leftMin+"\"\r\n vs \""+rightMin+"\"", path, comp.getMessages(), res.getMessages()); + } else { + vm(IssueSeverity.INFORMATION, "Element minimum cardinalities differ:\r\n \""+leftMin+"\"\r\n vs \""+rightMin+"\"", path, comp.getMessages(), res.getMessages()); + } + } + if (leftMax != rightMax) { + if (leftMax == Integer.MAX_VALUE) { + vm(IssueSeverity.INFORMATION, "Element maximum cardinalities differ:\r\n \""+leftMax+"\"\r\n vs \""+rightMax+"\"", path, comp.getMessages(), res.getMessages()); + } else if (rightMax == Integer.MAX_VALUE) { + vm(IssueSeverity.INFORMATION, "Element maximum cardinalities differ:\r\n \""+leftMax+"\"\r\n vs \""+rightMax+"\"", path, comp.getMessages(), res.getMessages()); + } else { + vm(IssueSeverity.INFORMATION, "Element maximum cardinalities differ:\r\n \""+leftMax+"\"\r\n vs \""+rightMax+"\"", path, comp.getMessages(), res.getMessages()); + } + } +// rule(comp, res, subset.getMax().equals("*") || Integer.parseInt(subset.getMax()) >= subset.getMin(), path, "Cardinality Mismatch: "+card(left)+"/"+card(right)); + + // cross comparison - if max > min in either direction, there can be no instances that are valid against both + if (leftMax < rightMin) { + vm(IssueSeverity.ERROR, "Element minimum cardinalities conflict:\r\n \""+leftMin+".."+leftMax+"\"\r\n vs \""+rightMin+".."+rightMax+"\": No instances can be valid against both profiles", path, comp.getMessages(), res.getMessages()); + } + if (rightMax < leftMin) { + vm(IssueSeverity.ERROR, "Element minimum cardinalities conflict:\r\n \""+leftMin+".."+leftMax+"\"\r\n vs \""+rightMin+".."+rightMax+"\": No instances can be valid against both profiles", path, comp.getMessages(), res.getMessages()); + } + } + private int unionMin(int left, int right) { if (left > right) return right; @@ -436,18 +486,14 @@ public class ProfileComparer extends CanonicalResourceComparer { return left; } - private String intersectMax(String left, String right) { - int l = "*".equals(left) ? Integer.MAX_VALUE : Integer.parseInt(left); - int r = "*".equals(right) ? Integer.MAX_VALUE : Integer.parseInt(right); + private String intersectMax(int l, int r, String left, String right) { if (l < r) return left; else return right; } - private String unionMax(String left, String right) { - int l = "*".equals(left) ? Integer.MAX_VALUE : Integer.parseInt(left); - int r = "*".equals(right) ? Integer.MAX_VALUE : Integer.parseInt(right); + private String unionMax(int l, int r, String left, String right) { if (l < r) return right; else @@ -480,7 +526,7 @@ public class ProfileComparer extends CanonicalResourceComparer { return Integer.toString(defn.current().getMin())+".."+defn.current().getMax(); } - private Collection unionTypes(ProfileComparison comp, StructuralMatch res, String path, List left, List right) throws DefinitionException, IOException, FHIRFormatError { + private Collection unionTypes(ProfileComparison comp, StructuralMatch res, String path, List left, List right) throws DefinitionException, IOException, FHIRFormatError { List result = new ArrayList(); for (TypeRefComponent l : left) checkAddTypeUnion(comp, res, path, result, l, session.getContextLeft()); @@ -489,7 +535,7 @@ public class ProfileComparer extends CanonicalResourceComparer { return result; } - private void checkAddTypeUnion(ProfileComparison comp, StructuralMatch res, String path, List results, TypeRefComponent nw, IWorkerContext ctxt) throws DefinitionException, IOException, FHIRFormatError { + private void checkAddTypeUnion(ProfileComparison comp, StructuralMatch res, String path, List results, TypeRefComponent nw, IWorkerContext ctxt) throws DefinitionException, IOException, FHIRFormatError { boolean pfound = false; boolean tfound = false; nw = nw.copy(); @@ -586,7 +632,7 @@ public class ProfileComparer extends CanonicalResourceComparer { return false; } - private Collection intersectTypes(ProfileComparison comp, StructuralMatch res, ElementDefinition ed, String path, List left, List right) throws DefinitionException, IOException, FHIRFormatError { + 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()) @@ -665,7 +711,7 @@ public class ProfileComparer extends CanonicalResourceComparer { return b.toString(); } - private boolean compareBindings(ProfileComparison comp, StructuralMatch res, ElementDefinition subset, ElementDefinition superset, String path, ElementDefinition lDef, ElementDefinition rDef) throws FHIRFormatError, DefinitionException, IOException { + private boolean compareBindings(ProfileComparison comp, StructuralMatch res, ElementDefinition subset, ElementDefinition superset, String path, ElementDefinition lDef, ElementDefinition rDef) throws FHIRFormatError, DefinitionException, IOException { assert(lDef.hasBinding() || rDef.hasBinding()); if (!lDef.hasBinding()) { subset.setBinding(rDef.getBinding()); @@ -801,7 +847,7 @@ public class ProfileComparer extends CanonicalResourceComparer { } // we can't really know about constraints. We create warnings, and collate them - private List unionConstraints(ProfileComparison comp, StructuralMatch res, String path, List left, List right) { + private List unionConstraints(ProfileComparison comp, StructuralMatch res, String path, List left, List right) { List result = new ArrayList(); for (ElementDefinitionConstraintComponent l : left) { boolean found = false; @@ -829,7 +875,7 @@ public class ProfileComparer extends CanonicalResourceComparer { return result; } - private StructureDefinition resolveProfile(ProfileComparison comp, StructuralMatch res, String path, String url, String name, IWorkerContext ctxt) { + private StructureDefinition resolveProfile(ProfileComparison comp, StructuralMatch res, String path, String url, String name, IWorkerContext ctxt) { StructureDefinition sd = ctxt.fetchResource(StructureDefinition.class, url); if (sd == null) { ValidationMessage vm = vmI(IssueSeverity.WARNING, "Unable to resolve profile "+url+" in profile "+name, path); @@ -841,7 +887,7 @@ public class ProfileComparer extends CanonicalResourceComparer { return binding.getStrength() == BindingStrength.EXAMPLE || binding.getStrength() == BindingStrength.PREFERRED; } - private ElementDefinitionBindingComponent unionBindings(ProfileComparison comp, StructuralMatch res, String path, ElementDefinitionBindingComponent left, ElementDefinitionBindingComponent right) throws FHIRFormatError, DefinitionException, IOException { + private ElementDefinitionBindingComponent unionBindings(ProfileComparison comp, StructuralMatch res, String path, ElementDefinitionBindingComponent left, ElementDefinitionBindingComponent right) throws FHIRFormatError, DefinitionException, IOException { ElementDefinitionBindingComponent union = new ElementDefinitionBindingComponent(); if (left.getStrength().compareTo(right.getStrength()) < 0) union.setStrength(left.getStrength()); @@ -881,17 +927,17 @@ public class ProfileComparer extends CanonicalResourceComparer { return gen.generate(model, prefix, 0, null); } - private void genElementComp(String defPath, HierarchicalTableGenerator gen, List rows, StructuralMatch combined, String corePath, String prefix, Row slicingRow, boolean root) throws IOException { + private void genElementComp(String defPath, HierarchicalTableGenerator gen, List rows, StructuralMatch combined, String corePath, String prefix, Row slicingRow, boolean root) throws IOException { Row originalRow = slicingRow; Row typesRow = null; - List> children = combined.getChildren(); + List> children = combined.getChildren(); Row row = gen.new Row(); rows.add(row); - String path = combined.either().getPath(); + String path = combined.either().getDef().getPath(); row.setAnchor(path); - row.setColor(utilsRight.getRowColor(combined.either(), false)); + row.setColor(utilsRight.getRowColor(combined.either().getDef(), false)); if (eitherHasSlicing(combined)) row.setLineColor(1); else if (eitherHasSliceName(combined)) @@ -917,7 +963,7 @@ public class ProfileComparer extends CanonicalResourceComparer { row.setIcon("icon_choice.gif", HierarchicalTableGenerator.TEXT_ICON_CHOICE); typesRow = row; } - } else if (combined.either().hasContentReference()) + } else if (combined.either().getDef().hasContentReference()) row.setIcon("icon_reuse.png", HierarchicalTableGenerator.TEXT_ICON_REUSE); else if (isPrimitive(combined)) row.setIcon("icon_primitive.png", HierarchicalTableGenerator.TEXT_ICON_PRIMITIVE); @@ -927,7 +973,7 @@ public class ProfileComparer extends CanonicalResourceComparer { row.setIcon("icon_datatype.gif", HierarchicalTableGenerator.TEXT_ICON_DATATYPE); else row.setIcon("icon_resource.png", HierarchicalTableGenerator.TEXT_ICON_RESOURCE); - String ref = defPath == null ? null : defPath + combined.either().getId(); + String ref = defPath == null ? null : defPath + combined.either().getDef().getId(); String sName = tail(path); String sn = getSliceName(combined); if (sn != null) @@ -937,23 +983,23 @@ public class ProfileComparer extends CanonicalResourceComparer { String leftColor = !combined.hasLeft() ? COLOR_NO_ROW_LEFT : combined.hasErrors() ? COLOR_DIFFERENT : null; String rightColor = !combined.hasRight() ? COLOR_NO_ROW_LEFT : combined.hasErrors() ? COLOR_DIFFERENT : null; if (combined.hasLeft()) { - nc = utilsRight.genElementNameCell(gen, combined.getLeft(), "??", true, corePath, prefix, root, false, false, null, typesRow, row, false, ext, used , ref, sName); + nc = utilsRight.genElementNameCell(gen, combined.getLeft().getDef(), "??", true, corePath, prefix, root, false, false, combined.getLeft().getSrc(), typesRow, row, false, ext, used , ref, sName); } else { - nc = utilsRight.genElementNameCell(gen, combined.getRight(), "??", true, corePath, prefix, root, false, false, null, typesRow, row, false, ext, used , ref, sName); + nc = utilsRight.genElementNameCell(gen, combined.getRight().getDef(), "??", true, corePath, prefix, root, false, false, combined.getRight().getSrc(), typesRow, row, false, ext, used , ref, sName); } if (combined.hasLeft()) { - frame(utilsRight.genElementCells(gen, combined.getLeft(), "??", true, corePath, prefix, root, false, false, null, typesRow, row, false, ext, used , ref, sName, nc, false), leftColor); + frame(utilsRight.genElementCells(gen, combined.getLeft().getDef(), "??", true, corePath, prefix, root, false, false, combined.getLeft().getSrc(), typesRow, row, true, ext, used , ref, sName, nc, false), leftColor); } else { frame(spacers(row, 4, gen), leftColor); } if (combined.hasRight()) { - frame(utilsRight.genElementCells(gen, combined.getRight(), "??", true, corePath, prefix, root, false, false, null, typesRow, row, false, ext, used, ref, sName, nc, false), rightColor); + frame(utilsRight.genElementCells(gen, combined.getRight().getDef(), "??", true, corePath, prefix, root, false, false, combined.getRight().getSrc(), typesRow, row, true, ext, used, ref, sName, nc, false), rightColor); } else { frame(spacers(row, 4, gen), rightColor); } row.getCells().add(cellForMessages(gen, combined.getMessages())); - for (StructuralMatch child : children) { + for (StructuralMatch child : children) { genElementComp(defPath, gen, row.getSubRows(), child, corePath, prefix, originalRow, false); } } @@ -978,47 +1024,47 @@ public class ProfileComparer extends CanonicalResourceComparer { return res; } - private String getSliceName(StructuralMatch combined) { + private String getSliceName(StructuralMatch combined) { // TODO Auto-generated method stub return null; } - private boolean isDataType(StructuralMatch combined) { + private boolean isDataType(StructuralMatch combined) { // TODO Auto-generated method stub return false; } - private boolean hasTarget(StructuralMatch combined) { + private boolean hasTarget(StructuralMatch combined) { // TODO Auto-generated method stub return false; } - private boolean isPrimitive(StructuralMatch combined) { + private boolean isPrimitive(StructuralMatch combined) { // TODO Auto-generated method stub return false; } - private boolean allAreReference(StructuralMatch combined) { + private boolean allAreReference(StructuralMatch combined) { // TODO Auto-generated method stub return false; } - private boolean hasChoice(StructuralMatch combined) { + private boolean hasChoice(StructuralMatch combined) { // TODO Auto-generated method stub return false; } - private boolean elementIsComplex(StructuralMatch combined) { + private boolean elementIsComplex(StructuralMatch combined) { // TODO Auto-generated method stub velement.hasType() && element.getType().get(0).hasProfile() && extensionIsComplex(element.getType().get(0).getProfile().get(0).getValue() return false; } - private boolean eitherHasSliceName(StructuralMatch combined) { + private boolean eitherHasSliceName(StructuralMatch combined) { // TODO Auto-generated method stub return false; } - private boolean eitherHasSlicing(StructuralMatch combined) { + private boolean eitherHasSlicing(StructuralMatch combined) { // TODO Auto-generated method stub return false; } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ResourceComparer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ResourceComparer.java index 92150276d..0da7d9d7e 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ResourceComparer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ResourceComparer.java @@ -301,11 +301,11 @@ public class ResourceComparer { private String halfColorForLevel(IssueSeverity level) { switch (level) { case ERROR: - return "#ffeeee"; + return "#ffdddd"; case FATAL: return "#ffcccc"; case WARNING: - return "#fff4ee"; + return "#fff6ee"; default: // INFORMATION: return "#fffff2"; } @@ -319,6 +319,9 @@ public class ResourceComparer { XhtmlNode li = new XhtmlNode(NodeType.Element, "li"); piece.getChildren().add(li); li.style("background-color: "+halfColorForLevel(msg.getLevel())); + if (msg.getLevel() == IssueSeverity.ERROR) { + li.style("font-weight: bold"); + } li.tx(msg.getMessage()); } return cell; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/StructuralMatch.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/StructuralMatch.java index 3b231d94e..7e96e8115 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/StructuralMatch.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/StructuralMatch.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.List; import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts; +import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; @@ -113,5 +114,6 @@ public class StructuralMatch { return this; } + } \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java index c73fdaf6f..9b10097ce 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java @@ -36,6 +36,9 @@ import java.io.FileReader; import java.io.IOException; import java.io.OutputStream; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -3504,7 +3507,7 @@ public class ProfileUtilities extends TranslatingUtilities { List types = e.getType(); if (!e.hasType()) { if (root) { // we'll use base instead of types then - StructureDefinition bsd = context.fetchResource(StructureDefinition.class, profile.getBaseDefinition()); + StructureDefinition bsd = profile == null ? null : context.fetchResource(StructureDefinition.class, profile.getBaseDefinition()); if (bsd != null) { if (bsd.hasUserData("path")) { c.getPieces().add(gen.new Piece(Utilities.isAbsoluteUrl(bsd.getUserString("path")) ? bsd.getUserString("path") : imagePath +bsd.getUserString("path"), bsd.getName(), null)); @@ -3586,7 +3589,7 @@ public class ProfileUtilities extends TranslatingUtilities { c.addPiece(checkForNoChange(tl, gen.new Piece(null,", ", null))); } - ref = pkp.getLinkForProfile(profile, p.getValue()); + ref = pkp == null ? null : pkp.getLinkForProfile(profile, p.getValue()); if (ref != null) { String[] parts = ref.split("\\|"); if (parts[0].startsWith("http:") || parts[0].startsWith("https:")) { @@ -3685,7 +3688,7 @@ public class ProfileUtilities extends TranslatingUtilities { private String checkPrepend(String corePath, String path) { - if (pkp.prependLinks() && !(path.startsWith("http:") || path.startsWith("https:"))) + if (pkp != null && pkp.prependLinks() && !(path.startsWith("http:") || path.startsWith("https:"))) return corePath+path; else return path; @@ -4566,7 +4569,7 @@ public class ProfileUtilities extends TranslatingUtilities { } } if (root) { - if (profile.getAbstract()) { + if (profile != null && profile.getAbstract()) { if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } c.addPiece(gen.new Piece(null, "This is an abstract profile", null)); } @@ -4661,7 +4664,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (binding!=null && !binding.isEmpty()) { if (!c.getPieces().isEmpty()) c.addPiece(gen.new Piece("br")); - BindingResolution br = pkp.resolveBinding(profile, binding, definition.getPath()); + BindingResolution br = pkp == null ? makeNullBr(binding) : pkp.resolveBinding(profile, binding, definition.getPath()); c.getPieces().add(checkForNoChange(binding, gen.new Piece(null, translate("sd.table", "Binding")+": ", null).addStyle("font-weight:bold"))); c.getPieces().add(checkForNoChange(binding.getValueSetElement(), gen.new Piece(br.url == null ? null : Utilities.isAbsoluteUrl(br.url) || !pkp.prependLinks() ? br.url : corePath+br.url, br.display, null))); if (binding.hasStrength()) { @@ -4670,7 +4673,7 @@ public class ProfileUtilities extends TranslatingUtilities { c.getPieces().add(checkForNoChange(binding.getStrengthElement(), gen.new Piece(null, ")", null))); } if (binding.hasExtension(ToolingExtensions.EXT_MAX_VALUESET)) { - br = pkp.resolveBinding(profile, ToolingExtensions.readStringExtension(binding, ToolingExtensions.EXT_MAX_VALUESET), definition.getPath()); + br = pkp == null ? makeNullBr(binding) : pkp.resolveBinding(profile, ToolingExtensions.readStringExtension(binding, ToolingExtensions.EXT_MAX_VALUESET), definition.getPath()); c.addPiece(gen.new Piece("br")); c.getPieces().add(checkForNoChange(binding, gen.new Piece(corePath+"extension-elementdefinition-maxvalueset.html", translate("sd.table", "Max Binding")+": ", "Max Value Set Extension").addStyle("font-weight:bold"))); c.getPieces().add(checkForNoChange(binding, gen.new Piece(br.url == null ? null : Utilities.isAbsoluteUrl(br.url) || !pkp.prependLinks() ? br.url : corePath+br.url, br.display, null))); @@ -4764,6 +4767,13 @@ public class ProfileUtilities extends TranslatingUtilities { return c; } + private BindingResolution makeNullBr(ElementDefinitionBindingComponent binding) { + BindingResolution br = new BindingResolution(); + br.url = "http://none.none/none"; + br.display = "todo"; + return br; + } + private ElementDefinitionBindingComponent makeUnifiedBinding(ElementDefinitionBindingComponent binding, ElementDefinition element) { if (!element.hasUserData(DERIVATION_POINTER)) { return binding; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/ExpressionNode.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/ExpressionNode.java index 0bffff94b..735b231a7 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/ExpressionNode.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/ExpressionNode.java @@ -614,6 +614,9 @@ public class ExpressionNode { public String check() { + if (kind == null) { + return "Error in expression - node has no kind"; + } switch (kind) { case Name: if (Utilities.noString(name)) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ToolingExtensions.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ToolingExtensions.java index da07639c6..284737538 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ToolingExtensions.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ToolingExtensions.java @@ -511,7 +511,7 @@ public class ToolingExtensions { * @return The extension, if on this element, else null */ public static Extension getExtension(DomainResource resource, String name) { - if (name == null) + if (resource == null || name == null) return null; if (!resource.hasExtension()) return null;