Merge pull request #376 from hapifhir/gg-v5122

Gg v5122
This commit is contained in:
Grahame Grieve 2020-11-13 15:31:02 +11:00 committed by GitHub
commit 3e7c3b01fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 355 additions and 233 deletions

View File

@ -0,0 +1,8 @@
Validator:
* Fix bug in unknown URL handling that could cause significant delays in validation (>1min / unknown URL)
* fix bug in processing excludes with filters in value sets
Other code changes:
* fix case problem with icons in questionnaire rendering
* fix problem with rendering nested slices on content references
* fix rendering on must-support view for must-support on types and target profiles

View File

@ -150,6 +150,26 @@ import org.hl7.fhir.utilities.xml.SchematronWriter.Section;
*/ */
public class ProfileUtilities extends TranslatingUtilities { public class ProfileUtilities extends TranslatingUtilities {
public class ElementDefinitionResolution {
private StructureDefinition source;
private ElementDefinition element;
public ElementDefinitionResolution(StructureDefinition source, ElementDefinition element) {
this.source = source;
this.element = element;
}
public StructureDefinition getSource() {
return source;
}
public ElementDefinition getElement() {
return element;
}
}
public class ElementRedirection { public class ElementRedirection {
private String path; private String path;
@ -1154,15 +1174,24 @@ public class ProfileUtilities extends TranslatingUtilities {
while (diffCursor <= diffLimit && differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), diffMatches.get(0).getPath()+".")) while (diffCursor <= diffLimit && differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), diffMatches.get(0).getPath()+"."))
diffCursor++; diffCursor++;
if (outcome.hasContentReference()) { if (outcome.hasContentReference()) {
ElementDefinition tgt = getElementById(srcSD, base.getElement(), outcome.getContentReference()); ElementDefinitionResolution tgt = getElementById(srcSD, base.getElement(), outcome.getContentReference());
if (tgt == null) if (tgt == null)
throw new DefinitionException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_REFERENCE_TO_, outcome.getContentReference())); throw new DefinitionException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_REFERENCE_TO_, outcome.getContentReference()));
replaceFromContentReference(outcome, tgt); replaceFromContentReference(outcome, tgt.getElement());
int nbc = base.getElement().indexOf(tgt)+1; if (tgt.getSource() != srcSD) {
base = tgt.getSource().getSnapshot();
int nbc = base.getElement().indexOf(tgt.getElement())+1;
int nbl = nbc; int nbl = nbc;
while (nbl < base.getElement().size() && base.getElement().get(nbl).getPath().startsWith(tgt.getPath()+".")) while (nbl < base.getElement().size() && base.getElement().get(nbl).getPath().startsWith(tgt.getElement().getPath()+"."))
nbl++; nbl++;
processPaths(indent+" ", result, base, differential, nbc, start - 1, nbl-1, diffCursor - 1, url, webUrl, profileName, tgt.getPath(), diffMatches.get(0).getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirectorStack(redirector, outcome, cpath), srcSD); processPaths(indent+" ", result, base, differential, nbc, start - 1, nbl-1, diffCursor - 1, url, webUrl, profileName, tgt.getElement().getPath(), diffMatches.get(0).getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirectorStack(redirector, outcome, cpath), tgt.getSource());
} else {
int nbc = base.getElement().indexOf(tgt.getElement())+1;
int nbl = nbc;
while (nbl < base.getElement().size() && base.getElement().get(nbl).getPath().startsWith(tgt.getElement().getPath()+"."))
nbl++;
processPaths(indent+" ", result, base, differential, nbc, start - 1, nbl-1, diffCursor - 1, url, webUrl, profileName, tgt.getElement().getPath(), diffMatches.get(0).getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirectorStack(redirector, outcome, cpath), srcSD);
}
} else { } else {
StructureDefinition dt = outcome.getType().size() == 1 ? getProfileForDataType(outcome.getType().get(0)) : getProfileForDataType("Element"); StructureDefinition dt = outcome.getType().size() == 1 ? getProfileForDataType(outcome.getType().get(0)) : getProfileForDataType("Element");
if (dt == null) if (dt == null)
@ -1263,16 +1292,6 @@ public class ProfileUtilities extends TranslatingUtilities {
e.getSlicing().addDiscriminator().setType(DiscriminatorType.TYPE).setPath("$this"); e.getSlicing().addDiscriminator().setType(DiscriminatorType.TYPE).setPath("$this");
e.getSlicing().setRules(SlicingRules.CLOSED); // type slicing is always closed; the differential might call it open, but that just means it's not constraining the slices it doesn't mention e.getSlicing().setRules(SlicingRules.CLOSED); // type slicing is always closed; the differential might call it open, but that just means it's not constraining the slices it doesn't mention
e.getSlicing().setOrdered(false); e.getSlicing().setOrdered(false);
// check that there's a slice for each allowed types
Set<String> allowedTypes = getListOfTypes(e);
for (TypeSlice t : typeList) {
allowedTypes.remove(t.type);
}
// GG - work in progress..
// if (!allowedTypes.isEmpty()) {
// System.out.println("!!: Error at "+cpath+": Allowed Types not sliced = "+allowedTypes);
// throw new Error("Error at "+cpath+": Allowed Types not sliced = "+allowedTypes);
// }
start++; start++;
@ -1305,7 +1324,32 @@ public class ProfileUtilities extends TranslatingUtilities {
} }
} }
} }
if (!"0".equals(e.getMax())) {
// check that there's a slice for each allowed types
Set<String> allowedTypes = getListOfTypes(e);
for (TypeSlice t : typeList) {
if (t.type != null) {
allowedTypes.remove(t.type);
} else if (t.getDefn().hasSliceName() && t.getDefn().getType().size() == 1) {
allowedTypes.remove(t.getDefn().getType().get(0).getCode());
}
}
if (!allowedTypes.isEmpty()) {
if (cpath.contains("xtension.value")) {
for (Iterator<TypeRefComponent> iter = e.getType().iterator(); iter.hasNext(); ) {
TypeRefComponent tr = iter.next();
if (allowedTypes.contains(tr.getCode())) {
iter.remove();
}
}
// System.out.println("!!: Extension Error at "+cpath+": Allowed Types not sliced = "+allowedTypes+". !Extension!!");
// throw new Error("Extension Error at "+cpath+": Allowed Types not sliced = "+allowedTypes+". !Extension!!");
} else {
e.getSlicing().setRules(SlicingRules.OPEN);
}
}
}
// ok, done with that - next in the base list // ok, done with that - next in the base list
baseCursor = nbl+1; baseCursor = nbl+1;
diffCursor = ndl+1; diffCursor = ndl+1;
@ -1989,7 +2033,7 @@ public class ProfileUtilities extends TranslatingUtilities {
private boolean diffsConstrainTypes(List<ElementDefinition> diffMatches, String cPath, List<TypeSlice> typeList) { private boolean diffsConstrainTypes(List<ElementDefinition> diffMatches, String cPath, List<TypeSlice> typeList) {
// if (diffMatches.size() < 2) // if (diffMatches.size() < 2)
// return false; // return false;
String p = diffMatches.get(0).getPath(); String p = diffMatches.get(0).getPath();
if (!p.endsWith("[x]") && !cPath.endsWith("[x]")) if (!p.endsWith("[x]") && !cPath.endsWith("[x]"))
return false; return false;
@ -2006,12 +2050,18 @@ public class ProfileUtilities extends TranslatingUtilities {
if (ed.hasSliceName() && ed.getType().size() == 1) { if (ed.hasSliceName() && ed.getType().size() == 1) {
typeList.add(new TypeSlice(ed, ed.getTypeFirstRep().getWorkingCode())); typeList.add(new TypeSlice(ed, ed.getTypeFirstRep().getWorkingCode()));
} else if (ed.hasSliceName() && ed.getType().size() == 0) { } else if (ed.hasSliceName() && ed.getType().size() == 0) {
String tn = ed.getSliceName().substring(rn.length()); if (isDataType(s)) {
typeList.add(new TypeSlice(ed, s));
} else if (isPrimitive(Utilities.uncapitalize(s))) {
typeList.add(new TypeSlice(ed, Utilities.uncapitalize(s)));
} else {
String tn = ed.getSliceName().substring(n.length());
if (isDataType(tn)) { if (isDataType(tn)) {
typeList.add(new TypeSlice(ed, tn)); typeList.add(new TypeSlice(ed, tn));
} else if (isPrimitive(Utilities.uncapitalize(tn))) { } else if (isPrimitive(Utilities.uncapitalize(tn))) {
typeList.add(new TypeSlice(ed, Utilities.uncapitalize(tn))); typeList.add(new TypeSlice(ed, Utilities.uncapitalize(tn)));
} }
}
} else if (!ed.hasSliceName() && !s.equals("[x]")) { } else if (!ed.hasSliceName() && !s.equals("[x]")) {
if (isDataType(s)) if (isDataType(s))
typeList.add(new TypeSlice(ed, s)); typeList.add(new TypeSlice(ed, s));
@ -3171,7 +3221,7 @@ public class ProfileUtilities extends TranslatingUtilities {
r1.getCells().add(gen.new Cell(null, defFile == null ? "" : defFile+"-definitions.html#extension."+ed.getName(), ((UriType) ued.getFixed()).getValue(), null, null)); r1.getCells().add(gen.new Cell(null, defFile == null ? "" : defFile+"-definitions.html#extension."+ed.getName(), ((UriType) ued.getFixed()).getValue(), null, null));
r1.getCells().add(gen.new Cell()); r1.getCells().add(gen.new Cell());
r1.getCells().add(gen.new Cell(null, null, describeCardinality(c, null, new UnusedTracker()), null, null)); r1.getCells().add(gen.new Cell(null, null, describeCardinality(c, null, new UnusedTracker()), null, null));
genTypes(gen, r1, ved, defFile, ed, corePath, imagePath, false); genTypes(gen, r1, ved, defFile, ed, corePath, imagePath, false, false);
Cell cell = gen.new Cell(); Cell cell = gen.new Cell();
cell.addMarkdown(c.getDefinition()); cell.addMarkdown(c.getDefinition());
r1.getCells().add(cell); r1.getCells().add(cell);
@ -3184,7 +3234,7 @@ public class ProfileUtilities extends TranslatingUtilities {
ved = ted; ved = ted;
} }
genTypes(gen, r, ved, defFile, ed, corePath, imagePath, false); genTypes(gen, r, ved, defFile, ed, corePath, imagePath, false, false);
r.setIcon("icon_"+m+"extension_simple.png", HierarchicalTableGenerator.TEXT_ICON_EXTENSION_SIMPLE); r.setIcon("icon_"+m+"extension_simple.png", HierarchicalTableGenerator.TEXT_ICON_EXTENSION_SIMPLE);
} }
@ -3243,7 +3293,7 @@ public class ProfileUtilities extends TranslatingUtilities {
private static final int AGG_GR = 2; private static final int AGG_GR = 2;
private static final boolean TABLE_FORMAT_FOR_FIXED_VALUES = false; private static final boolean TABLE_FORMAT_FOR_FIXED_VALUES = false;
private Cell genTypes(HierarchicalTableGenerator gen, Row r, ElementDefinition e, String profileBaseFileName, StructureDefinition profile, String corePath, String imagePath, boolean root) { private Cell genTypes(HierarchicalTableGenerator gen, Row r, ElementDefinition e, String profileBaseFileName, StructureDefinition profile, String corePath, String imagePath, boolean root, boolean mustSupportMode) {
Cell c = gen.new Cell(); Cell c = gen.new Cell();
r.getCells().add(c); r.getCells().add(c);
if (e.hasContentReference()) { if (e.hasContentReference()) {
@ -3294,6 +3344,7 @@ public class ProfileUtilities extends TranslatingUtilities {
TypeRefComponent tl = null; TypeRefComponent tl = null;
for (TypeRefComponent t : types) { for (TypeRefComponent t : types) {
if (!mustSupportMode || allTypesMustSupport(e) || isMustSupport(t)) {
if (first) { if (first) {
first = false; first = false;
} else { } else {
@ -3302,23 +3353,25 @@ public class ProfileUtilities extends TranslatingUtilities {
tl = t; tl = t;
if (t.hasTarget()) { if (t.hasTarget()) {
c.getPieces().add(gen.new Piece(corePath+"references.html", t.getWorkingCode(), null)); c.getPieces().add(gen.new Piece(corePath+"references.html", t.getWorkingCode(), null));
if (isMustSupportDirect(t) && e.getMustSupport()) { if (!mustSupportMode && isMustSupportDirect(t) && e.getMustSupport()) {
c.addPiece(gen.new Piece(null, " ", null)); c.addPiece(gen.new Piece(null, " ", null));
c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false); c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false);
} }
c.getPieces().add(gen.new Piece(null, "(", null)); c.getPieces().add(gen.new Piece(null, "(", null));
boolean tfirst = true; boolean tfirst = true;
for (CanonicalType u : t.getTargetProfile()) { for (CanonicalType u : t.getTargetProfile()) {
if (!mustSupportMode || allProfilesMustSupport(t.getTargetProfile()) || isMustSupport(u)) {
if (tfirst) if (tfirst)
tfirst = false; tfirst = false;
else else
c.addPiece(gen.new Piece(null, " | ", null)); c.addPiece(gen.new Piece(null, " | ", null));
genTargetLink(gen, profileBaseFileName, corePath, c, t, u.getValue()); genTargetLink(gen, profileBaseFileName, corePath, c, t, u.getValue());
if (isMustSupport(u) && e.getMustSupport()) { if (!mustSupportMode && isMustSupport(u) && e.getMustSupport()) {
c.addPiece(gen.new Piece(null, " ", null)); c.addPiece(gen.new Piece(null, " ", null));
c.addStyledText(translate("sd.table", "This target must be supported"), "S", "white", "red", null, false); c.addStyledText(translate("sd.table", "This target must be supported"), "S", "white", "red", null, false);
} }
} }
}
c.getPieces().add(gen.new Piece(null, ")", null)); c.getPieces().add(gen.new Piece(null, ")", null));
if (t.getAggregation().size() > 0) { if (t.getAggregation().size() > 0) {
c.getPieces().add(gen.new Piece(corePath+"valueset-resource-aggregation-mode.html", " {", null)); c.getPieces().add(gen.new Piece(corePath+"valueset-resource-aggregation-mode.html", " {", null));
@ -3336,6 +3389,7 @@ public class ProfileUtilities extends TranslatingUtilities {
String ref; String ref;
boolean pfirst = true; boolean pfirst = true;
for (CanonicalType p : t.getProfile()) { for (CanonicalType p : t.getProfile()) {
if (!mustSupportMode || allProfilesMustSupport(t.getProfile()) || isMustSupport(p)) {
if (pfirst) { if (pfirst) {
pfirst = false; pfirst = false;
} else { } else {
@ -3354,11 +3408,12 @@ public class ProfileUtilities extends TranslatingUtilities {
} }
} else } else
c.addPiece(checkForNoChange(t, gen.new Piece((p.getValue().startsWith(corePath)? corePath: "")+ref, t.getWorkingCode(), null))); c.addPiece(checkForNoChange(t, gen.new Piece((p.getValue().startsWith(corePath)? corePath: "")+ref, t.getWorkingCode(), null)));
if (isMustSupport(p) && e.getMustSupport()) { if (!mustSupportMode && isMustSupport(p) && e.getMustSupport()) {
c.addPiece(gen.new Piece(null, " ", null)); c.addPiece(gen.new Piece(null, " ", null));
c.addStyledText(translate("sd.table", "This profile must be supported"), "S", "white", "red", null, false); c.addStyledText(translate("sd.table", "This profile must be supported"), "S", "white", "red", null, false);
} }
} }
}
} else { } else {
String tc = t.getWorkingCode(); String tc = t.getWorkingCode();
if (Utilities.isAbsoluteUrl(tc)) { if (Utilities.isAbsoluteUrl(tc)) {
@ -3373,12 +3428,13 @@ public class ProfileUtilities extends TranslatingUtilities {
} else { } else {
c.addPiece(checkForNoChange(t, gen.new Piece(null, tc, null))); c.addPiece(checkForNoChange(t, gen.new Piece(null, tc, null)));
} }
if (isMustSupportDirect(t) && e.getMustSupport()) { if (!mustSupportMode && isMustSupportDirect(t) && e.getMustSupport()) {
c.addPiece(gen.new Piece(null, " ", null)); c.addPiece(gen.new Piece(null, " ", null));
c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false); c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false);
} }
} }
} }
}
return c; return c;
} }
@ -3485,7 +3541,7 @@ public class ProfileUtilities extends TranslatingUtilities {
// return null; // return null;
} }
private ElementDefinition getElementById(StructureDefinition source, List<ElementDefinition> elements, String contentReference) { private ElementDefinitionResolution getElementById(StructureDefinition source, List<ElementDefinition> elements, String contentReference) {
if (!contentReference.startsWith("#") && contentReference.contains("#")) { if (!contentReference.startsWith("#") && contentReference.contains("#")) {
String url = contentReference.substring(0, contentReference.indexOf("#")); String url = contentReference.substring(0, contentReference.indexOf("#"));
contentReference = contentReference.substring(contentReference.indexOf("#")); contentReference = contentReference.substring(contentReference.indexOf("#"));
@ -3499,7 +3555,7 @@ public class ProfileUtilities extends TranslatingUtilities {
} }
for (ElementDefinition ed : elements) for (ElementDefinition ed : elements)
if (ed.hasId() && ("#"+ed.getId()).equals(contentReference)) if (ed.hasId() && ("#"+ed.getId()).equals(contentReference))
return ed; return new ElementDefinitionResolution(source, ed);
return null; return null;
} }
@ -3882,7 +3938,7 @@ public class ProfileUtilities extends TranslatingUtilities {
// genElement(defPath, gen, row.getSubRows(), child, all, profiles, showMissing, profileBaseFileName, true, false, corePath, imagePath, false, logicalModel, isConstraintMode, allInvariants); // genElement(defPath, gen, row.getSubRows(), child, all, profiles, showMissing, profileBaseFileName, true, false, corePath, imagePath, false, logicalModel, isConstraintMode, allInvariants);
} }
if (typesRow != null) { if (typesRow != null) {
makeChoiceRows(typesRow.getSubRows(), element, gen, corePath, profileBaseFileName); makeChoiceRows(typesRow.getSubRows(), element, gen, corePath, profileBaseFileName, mustSupport);
} }
} }
return slicingRow; return slicingRow;
@ -3967,7 +4023,7 @@ public class ProfileUtilities extends TranslatingUtilities {
res.add(genCardinality(gen, element, row, hasDef, used, extDefn.getElement())); res.add(genCardinality(gen, element, row, hasDef, used, extDefn.getElement()));
ElementDefinition valueDefn = extDefn.getExtensionValueDefinition(); ElementDefinition valueDefn = extDefn.getExtensionValueDefinition();
if (valueDefn != null && !"0".equals(valueDefn.getMax())) if (valueDefn != null && !"0".equals(valueDefn.getMax()))
res.add(genTypes(gen, row, valueDefn, profileBaseFileName, profile, corePath, imagePath, root)); res.add(genTypes(gen, row, valueDefn, profileBaseFileName, profile, corePath, imagePath, root, mustSupport));
else // if it's complex, we just call it nothing else // if it's complex, we just call it nothing
// genTypes(gen, row, extDefn.getSnapshot().getElement().get(0), profileBaseFileName, profile); // genTypes(gen, row, extDefn.getSnapshot().getElement().get(0), profileBaseFileName, profile);
res.add(addCell(row, gen.new Cell(null, null, "("+translate("sd.table", "Complex")+")", null, null))); res.add(addCell(row, gen.new Cell(null, null, "("+translate("sd.table", "Complex")+")", null, null)));
@ -3978,7 +4034,7 @@ public class ProfileUtilities extends TranslatingUtilities {
if ("0".equals(element.getMax())) if ("0".equals(element.getMax()))
res.add(addCell(row, gen.new Cell())); res.add(addCell(row, gen.new Cell()));
else else
res.add(genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root)); res.add(genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root, mustSupport));
res.add(generateDescription(gen, row, element, (ElementDefinition) element.getUserData(DERIVATION_POINTER), used.used, null, null, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport)); res.add(generateDescription(gen, row, element, (ElementDefinition) element.getUserData(DERIVATION_POINTER), used.used, null, null, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport));
} }
} else { } else {
@ -3986,7 +4042,7 @@ public class ProfileUtilities extends TranslatingUtilities {
if (element.hasSlicing()) if (element.hasSlicing())
res.add(addCell(row, gen.new Cell(null, corePath+"profiling.html#slicing", "(Slice Definition)", null, null))); res.add(addCell(row, gen.new Cell(null, corePath+"profiling.html#slicing", "(Slice Definition)", null, null)));
else if (hasDef && !"0".equals(element.getMax()) && typesRow == null) else if (hasDef && !"0".equals(element.getMax()) && typesRow == null)
res.add(genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root)); res.add(genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root, mustSupport));
else else
res.add(addCell(row, gen.new Cell())); res.add(addCell(row, gen.new Cell()));
res.add(generateDescription(gen, row, element, (ElementDefinition) element.getUserData(DERIVATION_POINTER), used.used, null, null, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport)); res.add(generateDescription(gen, row, element, (ElementDefinition) element.getUserData(DERIVATION_POINTER), used.used, null, null, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport));
@ -4048,9 +4104,10 @@ public class ProfileUtilities extends TranslatingUtilities {
return key.startsWith("ele-") || key.startsWith("res-") || key.startsWith("ext-") || key.startsWith("dom-") || key.startsWith("dr-"); return key.startsWith("ele-") || key.startsWith("res-") || key.startsWith("ext-") || key.startsWith("dom-") || key.startsWith("dr-");
} }
private void makeChoiceRows(List<Row> subRows, ElementDefinition element, HierarchicalTableGenerator gen, String corePath, String profileBaseFileName) { private void makeChoiceRows(List<Row> subRows, ElementDefinition element, HierarchicalTableGenerator gen, String corePath, String profileBaseFileName, boolean mustSupportMode) {
// create a child for each choice // create a child for each choice
for (TypeRefComponent tr : element.getType()) { for (TypeRefComponent tr : element.getType()) {
if (!mustSupportMode || allTypesMustSupport(element) || isMustSupport(tr)) {
Row choicerow = gen.new Row(); Row choicerow = gen.new Row();
String t = tr.getWorkingCode(); String t = tr.getWorkingCode();
if (isReference(t)) { if (isReference(t)) {
@ -4065,7 +4122,7 @@ public class ProfileUtilities extends TranslatingUtilities {
c.getPieces().add(gen.new Piece(corePath+"datatypes.html#canonical", "canonical", null)); c.getPieces().add(gen.new Piece(corePath+"datatypes.html#canonical", "canonical", null));
else else
c.getPieces().add(gen.new Piece(corePath+"references.html#Reference", "Reference", null)); c.getPieces().add(gen.new Piece(corePath+"references.html#Reference", "Reference", null));
if (isMustSupportDirect(tr) && element.getMustSupport()) { if (!mustSupportMode && isMustSupportDirect(tr) && element.getMustSupport()) {
c.addPiece(gen.new Piece(null, " ", null)); c.addPiece(gen.new Piece(null, " ", null));
c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false); c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false);
} }
@ -4073,15 +4130,17 @@ public class ProfileUtilities extends TranslatingUtilities {
} }
boolean first = true; boolean first = true;
for (CanonicalType rt : tr.getTargetProfile()) { for (CanonicalType rt : tr.getTargetProfile()) {
if (!mustSupportMode || allProfilesMustSupport(tr.getTargetProfile()) || isMustSupport(rt)) {
if (!first) if (!first)
c.getPieces().add(gen.new Piece(null, " | ", null)); c.getPieces().add(gen.new Piece(null, " | ", null));
genTargetLink(gen, profileBaseFileName, corePath, c, tr, rt.getValue()); genTargetLink(gen, profileBaseFileName, corePath, c, tr, rt.getValue());
if (isMustSupport(rt) && element.getMustSupport()) { if (!mustSupportMode && isMustSupport(rt) && element.getMustSupport()) {
c.addPiece(gen.new Piece(null, " ", null)); c.addPiece(gen.new Piece(null, " ", null));
c.addStyledText(translate("sd.table", "This target must be supported"), "S", "white", "red", null, false); c.addStyledText(translate("sd.table", "This target must be supported"), "S", "white", "red", null, false);
} }
first = false; first = false;
} }
}
if (first) if (first)
c.getPieces().add(gen.new Piece(null, "Any", null)); c.getPieces().add(gen.new Piece(null, "Any", null));
@ -4100,7 +4159,7 @@ public class ProfileUtilities extends TranslatingUtilities {
choicerow.setIcon("icon_primitive.png", HierarchicalTableGenerator.TEXT_ICON_PRIMITIVE); choicerow.setIcon("icon_primitive.png", HierarchicalTableGenerator.TEXT_ICON_PRIMITIVE);
Cell c = gen.new Cell(null, corePath+"datatypes.html#"+t, sd.getType(), null, null); Cell c = gen.new Cell(null, corePath+"datatypes.html#"+t, sd.getType(), null, null);
choicerow.getCells().add(c); choicerow.getCells().add(c);
if (isMustSupport(tr) && element.getMustSupport()) { if (!mustSupportMode && isMustSupport(tr) && element.getMustSupport()) {
c.addPiece(gen.new Piece(null, " ", null)); c.addPiece(gen.new Piece(null, " ", null));
c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false); c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false);
} }
@ -4111,7 +4170,7 @@ public class ProfileUtilities extends TranslatingUtilities {
choicerow.setIcon("icon_datatype.gif", HierarchicalTableGenerator.TEXT_ICON_DATATYPE); choicerow.setIcon("icon_datatype.gif", HierarchicalTableGenerator.TEXT_ICON_DATATYPE);
Cell c = gen.new Cell(null, pkp.getLinkFor(corePath, t), sd.getType(), null, null); Cell c = gen.new Cell(null, pkp.getLinkFor(corePath, t), sd.getType(), null, null);
choicerow.getCells().add(c); choicerow.getCells().add(c);
if (isMustSupport(tr) && element.getMustSupport()) { if (!mustSupportMode && isMustSupport(tr) && element.getMustSupport()) {
c.addPiece(gen.new Piece(null, " ", null)); c.addPiece(gen.new Piece(null, " ", null));
c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false); c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false);
} }
@ -4121,17 +4180,18 @@ public class ProfileUtilities extends TranslatingUtilities {
typeCell.addPiece(gen.new Piece(null, "(", null)); typeCell.addPiece(gen.new Piece(null, "(", null));
boolean first = true; boolean first = true;
for (CanonicalType pt : tr.getProfile()) { for (CanonicalType pt : tr.getProfile()) {
if (!mustSupportMode || allProfilesMustSupport(tr.getProfile()) || isMustSupport(pt)) {
if (first) first = false; else typeCell.addPiece(gen.new Piece(null, " | ", null)); if (first) first = false; else typeCell.addPiece(gen.new Piece(null, " | ", null));
StructureDefinition psd = context.fetchResource(StructureDefinition.class, pt.getValue()); StructureDefinition psd = context.fetchResource(StructureDefinition.class, pt.getValue());
if (psd == null) if (psd == null)
typeCell.addPiece(gen.new Piece(null, "?gen-e2?", null)); typeCell.addPiece(gen.new Piece(null, "?gen-e2?", null));
else else
typeCell.addPiece(gen.new Piece(psd.getUserString("path"), psd.getName(), psd.present())); typeCell.addPiece(gen.new Piece(psd.getUserString("path"), psd.getName(), psd.present()));
if (isMustSupport(pt) && element.getMustSupport()) { if (!mustSupportMode && isMustSupport(pt) && element.getMustSupport()) {
typeCell.addPiece(gen.new Piece(null, " ", null)); typeCell.addPiece(gen.new Piece(null, " ", null));
typeCell.addStyledText(translate("sd.table", "This profile must be supported"), "S", "white", "red", null, false); typeCell.addStyledText(translate("sd.table", "This profile must be supported"), "S", "white", "red", null, false);
} }
}
} }
typeCell.addPiece(gen.new Piece(null, ")", null)); typeCell.addPiece(gen.new Piece(null, ")", null));
} }
@ -4140,6 +4200,7 @@ public class ProfileUtilities extends TranslatingUtilities {
subRows.add(choicerow); subRows.add(choicerow);
} }
} }
}
private boolean isReference(String t) { private boolean isReference(String t) {
return t.equals("Reference") || t.equals("canonical"); return t.equals("Reference") || t.equals("canonical");
@ -4182,7 +4243,7 @@ public class ProfileUtilities extends TranslatingUtilities {
ExtensionContext extDefn = null; ExtensionContext extDefn = null;
genCardinality(gen, element, row, hasDef, used, null); genCardinality(gen, element, row, hasDef, used, null);
if (hasDef && !"0".equals(element.getMax())) if (hasDef && !"0".equals(element.getMax()))
genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root); genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root, false);
else else
row.getCells().add(gen.new Cell()); row.getCells().add(gen.new Cell());
generateGridDescription(gen, row, element, null, used.used, null, null, profile, corePath, imagePath, root, null); generateGridDescription(gen, row, element, null, used.used, null, null, profile, corePath, imagePath, root, null);
@ -5072,6 +5133,9 @@ public class ProfileUtilities extends TranslatingUtilities {
if (ref.substring(1, 2).toUpperCase().equals(ref.substring(1,2))) { if (ref.substring(1, 2).toUpperCase().equals(ref.substring(1,2))) {
actual = base+(ref.substring(1)+"."+path.substring(p.length()+1)).substring(prefixLength); actual = base+(ref.substring(1)+"."+path.substring(p.length()+1)).substring(prefixLength);
path = actual; path = actual;
} else if (ref.startsWith("http:")) {
actual = base+(ref.substring(ref.indexOf("#")+1)+"."+path.substring(p.length()+1)).substring(prefixLength);
path = actual;
} else { } else {
// Older versions of FHIR (e.g. 2016May) had reference of the style #parameter instead of #Parameters.parameter, so we have to handle that // Older versions of FHIR (e.g. 2016May) had reference of the style #parameter instead of #Parameters.parameter, so we have to handle that
actual = base+(path.substring(0, path.indexOf(".")+1) + ref.substring(1)+"."+path.substring(p.length()+1)).substring(prefixLength); actual = base+(path.substring(0, path.indexOf(".")+1) + ref.substring(1)+"."+path.substring(p.length()+1)).substring(prefixLength);
@ -6365,6 +6429,25 @@ public class ProfileUtilities extends TranslatingUtilities {
return grp; return grp;
} }
public static boolean allTypesMustSupport(ElementDefinition e) {
boolean all = true;
boolean any = false;
for (TypeRefComponent tr : e.getType()) {
all = all && isMustSupport(tr);
any = any || isMustSupport(tr);
}
return !all && !any;
}
public static boolean allProfilesMustSupport(List<CanonicalType> profiles) {
boolean all = true;
boolean any = false;
for (CanonicalType u : profiles) {
all = all && isMustSupport(u);
any = any || isMustSupport(u);
}
return !all && !any;
}
public static boolean isMustSupportDirect(TypeRefComponent tr) { public static boolean isMustSupportDirect(TypeRefComponent tr) {
return ("true".equals(ToolingExtensions.readStringExtension(tr, ToolingExtensions.EXT_MUST_SUPPORT))); return ("true".equals(ToolingExtensions.readStringExtension(tr, ToolingExtensions.EXT_MUST_SUPPORT)));
} }

View File

@ -142,7 +142,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer {
rows.add(r); rows.add(r);
boolean hasExt = false; boolean hasExt = false;
r.setIcon("icon-q-"+i.getType().toCode()+".png", i.getType().getDisplay()); r.setIcon("icon-q-"+i.getType().toCode().toLowerCase()+".png", i.getType().getDisplay());
r.getCells().add(gen.new Cell(null, context.getDefinitionsTarget() == null ? "" : context.getDefinitionsTarget()+"#item."+i.getLinkId(), i.getLinkId(), null, null)); r.getCells().add(gen.new Cell(null, context.getDefinitionsTarget() == null ? "" : context.getDefinitionsTarget()+"#item."+i.getLinkId(), i.getLinkId(), null, null));
String txt = (i.hasPrefix() ? i.getPrefix() + ". " : "") + i.getText(); String txt = (i.hasPrefix() ? i.getPrefix() + ". " : "") + i.getText();
r.getCells().add(gen.new Cell(null, null, txt, null, null)); r.getCells().add(gen.new Cell(null, null, txt, null, null));
@ -361,7 +361,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer {
rows.add(r); rows.add(r);
boolean hasExt = false; boolean hasExt = false;
r.setIcon("icon-q-"+i.getType().toCode()+".png", i.getType().getDisplay()); r.setIcon("icon-q-"+i.getType().toCode().toLowerCase()+".png", i.getType().getDisplay());
r.getCells().add(gen.new Cell(null, context.getDefinitionsTarget() == null ? "" : context.getDefinitionsTarget()+"#item."+i.getLinkId(), i.getLinkId(), null, null)); r.getCells().add(gen.new Cell(null, context.getDefinitionsTarget() == null ? "" : context.getDefinitionsTarget()+"#item."+i.getLinkId(), i.getLinkId(), null, null));
Cell defn = gen.new Cell(); Cell defn = gen.new Cell();
r.getCells().add(defn); r.getCells().add(defn);

View File

@ -523,14 +523,13 @@ public class ValueSetCheckerSimple implements ValueSetChecker {
} else { } else {
if (vsi.hasFilter()) { if (vsi.hasFilter()) {
boolean ok = true; boolean ok = true;
for (ConceptSetFilterComponent f : vsi.getFilter()) for (ConceptSetFilterComponent f : vsi.getFilter()) {
if (!codeInFilter(cs, system, f, code)) { if (!codeInFilter(cs, system, f, code)) {
ok = false; ok = false;
break; break;
} }
if (ok) {
return true;
} }
return ok;
} }
List<ConceptDefinitionComponent> list = cs.getConcept(); List<ConceptDefinitionComponent> list = cs.getConcept();

View File

@ -41,6 +41,7 @@ import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.json.JSONUtil; import org.hl7.fhir.utilities.json.JSONUtil;
import org.hl7.fhir.utilities.json.JsonTrackingParser;
import org.hl7.fhir.utilities.npm.NpmPackage.NpmPackageFolder; import org.hl7.fhir.utilities.npm.NpmPackage.NpmPackageFolder;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -549,7 +550,9 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
@Override @Override
public String getPackageId(String canonicalUrl) throws IOException { public String getPackageId(String canonicalUrl) throws IOException {
String retVal = super.getPackageId(canonicalUrl); String retVal = findCanonicalInLocalCache(canonicalUrl);
retVal = super.getPackageId(canonicalUrl);
if (retVal == null) { if (retVal == null) {
retVal = getPackageIdFromBuildList(canonicalUrl); retVal = getPackageIdFromBuildList(canonicalUrl);
@ -559,6 +562,21 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
} }
public String findCanonicalInLocalCache(String canonicalUrl) {
try {
for (String pf : listPackages()) {
if (new File(Utilities.path(cacheFolder, pf, "package", "package.json")).exists()) {
JsonObject npm = JsonTrackingParser.parseJsonFile(Utilities.path(cacheFolder, pf, "package", "package.json"));
if (canonicalUrl.equals(JSONUtil.str(npm, "canonical"))) {
return JSONUtil.str(npm, "name");
}
}
}
} catch (IOException e) {
}
return null;
}
// ========================= Package Mgmt API ======================================================================= // ========================= Package Mgmt API =======================================================================
private String getPackageIdFromBuildList(String canonical) throws IOException { private String getPackageIdFromBuildList(String canonical) throws IOException {

View File

@ -25,7 +25,7 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher {
void loadPackage(String id, String ver) throws IOException, FHIRException; void loadPackage(String id, String ver) throws IOException, FHIRException;
} }
private BasePackageCacheManager pcm; private FilesystemPackageCacheManager pcm;
private IWorkerContext context; private IWorkerContext context;
private IPackageInstaller installer; private IPackageInstaller installer;
@ -51,19 +51,37 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher {
if (!Utilities.isAbsoluteUrl(url)) { if (!Utilities.isAbsoluteUrl(url)) {
return false; return false;
} }
// if we've got to here, it's a reference to a FHIR URL. We're going to try to resolve it on the fly
// if we've got to here, it's a reference to a FHIR URL. We're going to try to resolve it on the fly
String pid = null;
String ver = null;
String base = findBaseUrl(url);
if (base == null) {
return false;
}
if (base.equals("http://terminology.hl7.org")) {
pid = "hl7.terminology";
} else if (url.startsWith("http://hl7.org/fhir")) {
pid = pcm.getPackageId(base);
} else {
pid = pcm.findCanonicalInLocalCache(base);
}
ver = url.contains("|") ? url.substring(url.indexOf("|")+1) : null;
if (pid == null) {
return false;
}
if (url.startsWith("http://hl7.org/fhir")) {
// first possibility: it's a reference to a version specific URL http://hl7.org/fhir/X.X/... // first possibility: it's a reference to a version specific URL http://hl7.org/fhir/X.X/...
VersionURLInfo vu = VersionUtilities.parseVersionUrl(url); VersionURLInfo vu = VersionUtilities.parseVersionUrl(url);
if (vu != null) { if (vu != null) {
NpmPackage pi = pcm.loadPackage(VersionUtilities.packageForVersion(vu.getVersion()), VersionUtilities.getCurrentVersion(vu.getVersion())); NpmPackage pi = pcm.loadPackage(VersionUtilities.packageForVersion(vu.getVersion()), VersionUtilities.getCurrentVersion(vu.getVersion()));
return pi.hasCanonical(vu.getUrl()); return pi.hasCanonical(vu.getUrl());
} }
}
// ok maybe it's a reference to a package we know // ok maybe it's a reference to a package we know
String base = findBaseUrl(url);
String pid = pcm.getPackageId(base);
String ver = url.contains("|") ? url.substring(url.indexOf("|")+1) : null;
if (pid != null) { if (pid != null) {
if (installer.packageExists(pid, ver)) { if (installer.packageExists(pid, ver)) {
installer.loadPackage(pid, ver); installer.loadPackage(pid, ver);
@ -72,13 +90,8 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher {
} }
} }
if (!url.startsWith("http://hl7.org/fhir")) { // we don't bother with urls outside fhir space in the standalone validator - we assume they are valid
return true; // we don't bother with those in the standalone validator - we assume they are valid return !url.startsWith("http://hl7.org/fhir");
}
// we assume it's invalid at this point
return false;
} }
private String findBaseUrl(String url) { private String findBaseUrl(String url) {

View File

@ -209,6 +209,7 @@ public class ValidationService {
FhirPublication ver = FhirPublication.fromCode(cliContext.getSv()); FhirPublication ver = FhirPublication.fromCode(cliContext.getSv());
ValidationEngine validator = new ValidationEngine(definitions, ver, cliContext.getSv(), tt); ValidationEngine validator = new ValidationEngine(definitions, ver, cliContext.getSv(), tt);
System.out.println(" - "+validator.getContext().countAllCaches()+" resources ("+tt.milestone()+")"); System.out.println(" - "+validator.getContext().countAllCaches()+" resources ("+tt.milestone()+")");
validator.loadIg("hl7.terminology", false);
System.out.print(" Terminology server " + cliContext.getTxServer()); System.out.print(" Terminology server " + cliContext.getTxServer());
String txver = validator.setTerminologyServer(cliContext.getTxServer(), cliContext.getTxLog(), ver); String txver = validator.setTerminologyServer(cliContext.getTxServer(), cliContext.getTxLog(), ver);
System.out.println(" - Version "+txver+" ("+tt.milestone()+")"); System.out.println(" - Version "+txver+" ("+tt.milestone()+")");

View File

@ -19,7 +19,7 @@
<properties> <properties>
<hapi_fhir_version>5.1.0</hapi_fhir_version> <hapi_fhir_version>5.1.0</hapi_fhir_version>
<validator_test_case_version>1.1.49</validator_test_case_version> <validator_test_case_version>1.1.50-SNAPSHOT</validator_test_case_version>
<junit_jupiter_version>5.6.2</junit_jupiter_version> <junit_jupiter_version>5.6.2</junit_jupiter_version>
<maven_surefire_version>3.0.0-M4</maven_surefire_version> <maven_surefire_version>3.0.0-M4</maven_surefire_version>
<jacoco_version>0.8.5</jacoco_version> <jacoco_version>0.8.5</jacoco_version>