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 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 {
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()+"."))
diffCursor++;
if (outcome.hasContentReference()) {
ElementDefinition tgt = getElementById(srcSD, base.getElement(), outcome.getContentReference());
ElementDefinitionResolution tgt = getElementById(srcSD, base.getElement(), outcome.getContentReference());
if (tgt == null)
throw new DefinitionException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_REFERENCE_TO_, outcome.getContentReference()));
replaceFromContentReference(outcome, tgt);
int nbc = base.getElement().indexOf(tgt)+1;
int nbl = nbc;
while (nbl < base.getElement().size() && base.getElement().get(nbl).getPath().startsWith(tgt.getPath()+"."))
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);
replaceFromContentReference(outcome, tgt.getElement());
if (tgt.getSource() != srcSD) {
base = tgt.getSource().getSnapshot();
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), 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 {
StructureDefinition dt = outcome.getType().size() == 1 ? getProfileForDataType(outcome.getType().get(0)) : getProfileForDataType("Element");
if (dt == null)
@ -1232,25 +1261,25 @@ public class ProfileUtilities extends TranslatingUtilities {
}
// check the slice names too while we're at it...
for (TypeSlice ts : typeList) {
if (ts.type != null) {
String tn = rootName(cpath)+Utilities.capitalize(ts.type);
if (!ts.defn.hasSliceName()) {
ts.defn.setSliceName(tn);
} else if (!ts.defn.getSliceName().equals(tn)) {
if (autoFixSliceNames) {
if (ts.type != null) {
String tn = rootName(cpath)+Utilities.capitalize(ts.type);
if (!ts.defn.hasSliceName()) {
ts.defn.setSliceName(tn);
} else {
throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_NAME_MUST_BE__BUT_IS_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath), tn, ts.defn.getSliceName()));
} else if (!ts.defn.getSliceName().equals(tn)) {
if (autoFixSliceNames) {
ts.defn.setSliceName(tn);
} else {
throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_NAME_MUST_BE__BUT_IS_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath), tn, ts.defn.getSliceName()));
}
} if (!ts.defn.hasType()) {
ts.defn.addType().setCode(ts.type);
} else if (ts.defn.getType().size() > 1) {
throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_FOR_TYPE__HAS_MORE_THAN_ONE_TYPE_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath), tn, ts.defn.typeSummary()));
} else if (!ts.defn.getType().get(0).getCode().equals(ts.type)) {
throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_FOR_TYPE__HAS_WRONG_TYPE_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath), tn, ts.defn.typeSummary()));
}
} if (!ts.defn.hasType()) {
ts.defn.addType().setCode(ts.type);
} else if (ts.defn.getType().size() > 1) {
throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_FOR_TYPE__HAS_MORE_THAN_ONE_TYPE_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath), tn, ts.defn.typeSummary()));
} else if (!ts.defn.getType().get(0).getCode().equals(ts.type)) {
throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_FOR_TYPE__HAS_WRONG_TYPE_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath), tn, ts.defn.typeSummary()));
}
}
}
// ok passed the checks.
// copy the root diff, and then process any children it has
@ -1263,17 +1292,7 @@ public class ProfileUtilities extends TranslatingUtilities {
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().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++;
String fixedType = null;
@ -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
baseCursor = nbl+1;
diffCursor = ndl+1;
@ -1989,7 +2033,7 @@ public class ProfileUtilities extends TranslatingUtilities {
private boolean diffsConstrainTypes(List<ElementDefinition> diffMatches, String cPath, List<TypeSlice> typeList) {
// if (diffMatches.size() < 2)
// return false;
// return false;
String p = diffMatches.get(0).getPath();
if (!p.endsWith("[x]") && !cPath.endsWith("[x]"))
return false;
@ -2006,11 +2050,17 @@ public class ProfileUtilities extends TranslatingUtilities {
if (ed.hasSliceName() && ed.getType().size() == 1) {
typeList.add(new TypeSlice(ed, ed.getTypeFirstRep().getWorkingCode()));
} else if (ed.hasSliceName() && ed.getType().size() == 0) {
String tn = ed.getSliceName().substring(rn.length());
if (isDataType(tn)) {
typeList.add(new TypeSlice(ed, tn));
} else if (isPrimitive(Utilities.uncapitalize(tn))) {
typeList.add(new TypeSlice(ed, Utilities.uncapitalize(tn)));
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)) {
typeList.add(new TypeSlice(ed, tn));
} else if (isPrimitive(Utilities.uncapitalize(tn))) {
typeList.add(new TypeSlice(ed, Utilities.uncapitalize(tn)));
}
}
} else if (!ed.hasSliceName() && !s.equals("[x]")) {
if (isDataType(s))
@ -2020,9 +2070,9 @@ public class ProfileUtilities extends TranslatingUtilities {
else if (isPrimitive(Utilities.uncapitalize(s)))
typeList.add(new TypeSlice(ed, Utilities.uncapitalize(s)));
} else if (!ed.hasSliceName() && s.equals("[x]"))
typeList.add(new TypeSlice(ed, null));
}
}
typeList.add(new TypeSlice(ed, null));
}
}
return true;
}
@ -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());
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.addMarkdown(c.getDefinition());
r1.getCells().add(cell);
@ -3184,7 +3234,7 @@ public class ProfileUtilities extends TranslatingUtilities {
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);
}
@ -3243,7 +3293,7 @@ public class ProfileUtilities extends TranslatingUtilities {
private static final int AGG_GR = 2;
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();
r.getCells().add(c);
if (e.hasContentReference()) {
@ -3294,88 +3344,94 @@ public class ProfileUtilities extends TranslatingUtilities {
TypeRefComponent tl = null;
for (TypeRefComponent t : types) {
if (first) {
first = false;
} else {
c.addPiece(checkForNoChange(tl, gen.new Piece(null,", ", null)));
}
tl = t;
if (t.hasTarget()) {
c.getPieces().add(gen.new Piece(corePath+"references.html", t.getWorkingCode(), null));
if (isMustSupportDirect(t) && e.getMustSupport()) {
c.addPiece(gen.new Piece(null, " ", null));
c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false);
if (!mustSupportMode || allTypesMustSupport(e) || isMustSupport(t)) {
if (first) {
first = false;
} else {
c.addPiece(checkForNoChange(tl, gen.new Piece(null,", ", null)));
}
c.getPieces().add(gen.new Piece(null, "(", null));
boolean tfirst = true;
for (CanonicalType u : t.getTargetProfile()) {
if (tfirst)
tfirst = false;
else
c.addPiece(gen.new Piece(null, " | ", null));
genTargetLink(gen, profileBaseFileName, corePath, c, t, u.getValue());
if (isMustSupport(u) && e.getMustSupport()) {
tl = t;
if (t.hasTarget()) {
c.getPieces().add(gen.new Piece(corePath+"references.html", t.getWorkingCode(), null));
if (!mustSupportMode && isMustSupportDirect(t) && e.getMustSupport()) {
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 type must be supported"), "S", "white", "red", null, false);
}
}
c.getPieces().add(gen.new Piece(null, ")", null));
if (t.getAggregation().size() > 0) {
c.getPieces().add(gen.new Piece(corePath+"valueset-resource-aggregation-mode.html", " {", null));
boolean firstA = true;
for (Enumeration<AggregationMode> a : t.getAggregation()) {
if (firstA = true)
firstA = false;
else
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", codeForAggregation(a.getValue()), hintForAggregation(a.getValue())));
}
c.getPieces().add(gen.new Piece(corePath+"valueset-resource-aggregation-mode.html", "}", null));
}
} else if (t.hasProfile() && (!t.getWorkingCode().equals("Extension") || isProfiledType(t.getProfile()))) { // a profiled type
String ref;
boolean pfirst = true;
for (CanonicalType p : t.getProfile()) {
if (pfirst) {
pfirst = false;
} else {
c.addPiece(checkForNoChange(tl, gen.new Piece(null,", ", null)));
}
ref = pkp.getLinkForProfile(profile, p.getValue());
if (ref != null) {
String[] parts = ref.split("\\|");
if (parts[0].startsWith("http:") || parts[0].startsWith("https:")) {
// c.addPiece(checkForNoChange(t, gen.new Piece(parts[0], "<" + parts[1] + ">", t.getCode()))); Lloyd
c.addPiece(checkForNoChange(t, gen.new Piece(parts[0], parts[1], t.getWorkingCode())));
} else {
// c.addPiece(checkForNoChange(t, gen.new Piece((t.getProfile().startsWith(corePath)? corePath: "")+parts[0], "<" + parts[1] + ">", t.getCode())));
c.addPiece(checkForNoChange(t, gen.new Piece((p.getValue().startsWith(corePath+"StructureDefinition")? corePath: "")+parts[0], parts[1], t.getWorkingCode())));
c.getPieces().add(gen.new Piece(null, "(", null));
boolean tfirst = true;
for (CanonicalType u : t.getTargetProfile()) {
if (!mustSupportMode || allProfilesMustSupport(t.getTargetProfile()) || isMustSupport(u)) {
if (tfirst)
tfirst = false;
else
c.addPiece(gen.new Piece(null, " | ", null));
genTargetLink(gen, profileBaseFileName, corePath, c, t, u.getValue());
if (!mustSupportMode && isMustSupport(u) && e.getMustSupport()) {
c.addPiece(gen.new Piece(null, " ", null));
c.addStyledText(translate("sd.table", "This target must be supported"), "S", "white", "red", null, false);
}
}
} else
c.addPiece(checkForNoChange(t, gen.new Piece((p.getValue().startsWith(corePath)? corePath: "")+ref, t.getWorkingCode(), null)));
if (isMustSupport(p) && e.getMustSupport()) {
c.addPiece(gen.new Piece(null, " ", null));
c.addStyledText(translate("sd.table", "This profile must be supported"), "S", "white", "red", null, false);
}
}
} else {
String tc = t.getWorkingCode();
if (Utilities.isAbsoluteUrl(tc)) {
StructureDefinition sd = context.fetchTypeDefinition(tc);
if (sd == null) {
c.getPieces().add(gen.new Piece(null, ")", null));
if (t.getAggregation().size() > 0) {
c.getPieces().add(gen.new Piece(corePath+"valueset-resource-aggregation-mode.html", " {", null));
boolean firstA = true;
for (Enumeration<AggregationMode> a : t.getAggregation()) {
if (firstA = true)
firstA = false;
else
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", codeForAggregation(a.getValue()), hintForAggregation(a.getValue())));
}
c.getPieces().add(gen.new Piece(corePath+"valueset-resource-aggregation-mode.html", "}", null));
}
} else if (t.hasProfile() && (!t.getWorkingCode().equals("Extension") || isProfiledType(t.getProfile()))) { // a profiled type
String ref;
boolean pfirst = true;
for (CanonicalType p : t.getProfile()) {
if (!mustSupportMode || allProfilesMustSupport(t.getProfile()) || isMustSupport(p)) {
if (pfirst) {
pfirst = false;
} else {
c.addPiece(checkForNoChange(tl, gen.new Piece(null,", ", null)));
}
ref = pkp.getLinkForProfile(profile, p.getValue());
if (ref != null) {
String[] parts = ref.split("\\|");
if (parts[0].startsWith("http:") || parts[0].startsWith("https:")) {
// c.addPiece(checkForNoChange(t, gen.new Piece(parts[0], "<" + parts[1] + ">", t.getCode()))); Lloyd
c.addPiece(checkForNoChange(t, gen.new Piece(parts[0], parts[1], t.getWorkingCode())));
} else {
// c.addPiece(checkForNoChange(t, gen.new Piece((t.getProfile().startsWith(corePath)? corePath: "")+parts[0], "<" + parts[1] + ">", t.getCode())));
c.addPiece(checkForNoChange(t, gen.new Piece((p.getValue().startsWith(corePath+"StructureDefinition")? corePath: "")+parts[0], parts[1], t.getWorkingCode())));
}
} else
c.addPiece(checkForNoChange(t, gen.new Piece((p.getValue().startsWith(corePath)? corePath: "")+ref, t.getWorkingCode(), null)));
if (!mustSupportMode && isMustSupport(p) && e.getMustSupport()) {
c.addPiece(gen.new Piece(null, " ", null));
c.addStyledText(translate("sd.table", "This profile must be supported"), "S", "white", "red", null, false);
}
}
}
} else {
String tc = t.getWorkingCode();
if (Utilities.isAbsoluteUrl(tc)) {
StructureDefinition sd = context.fetchTypeDefinition(tc);
if (sd == null) {
c.addPiece(checkForNoChange(t, gen.new Piece(pkp.getLinkFor(corePath, tc), tc, null)));
} else {
c.addPiece(checkForNoChange(t, gen.new Piece(pkp.getLinkFor(corePath, tc), sd.getType(), null)));
}
} else if (pkp != null && pkp.hasLinkFor(tc)) {
c.addPiece(checkForNoChange(t, gen.new Piece(pkp.getLinkFor(corePath, tc), tc, null)));
} else {
c.addPiece(checkForNoChange(t, gen.new Piece(pkp.getLinkFor(corePath, tc), sd.getType(), null)));
c.addPiece(checkForNoChange(t, gen.new Piece(null, tc, null)));
}
if (!mustSupportMode && isMustSupportDirect(t) && e.getMustSupport()) {
c.addPiece(gen.new Piece(null, " ", null));
c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false);
}
} else if (pkp != null && pkp.hasLinkFor(tc)) {
c.addPiece(checkForNoChange(t, gen.new Piece(pkp.getLinkFor(corePath, tc), tc, null)));
} else {
c.addPiece(checkForNoChange(t, gen.new Piece(null, tc, null)));
}
if (isMustSupportDirect(t) && e.getMustSupport()) {
c.addPiece(gen.new Piece(null, " ", null));
c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false);
}
}
}
@ -3485,7 +3541,7 @@ public class ProfileUtilities extends TranslatingUtilities {
// 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("#")) {
String url = contentReference.substring(0, contentReference.indexOf("#"));
contentReference = contentReference.substring(contentReference.indexOf("#"));
@ -3499,7 +3555,7 @@ public class ProfileUtilities extends TranslatingUtilities {
}
for (ElementDefinition ed : elements)
if (ed.hasId() && ("#"+ed.getId()).equals(contentReference))
return ed;
return new ElementDefinitionResolution(source, ed);
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);
}
if (typesRow != null) {
makeChoiceRows(typesRow.getSubRows(), element, gen, corePath, profileBaseFileName);
makeChoiceRows(typesRow.getSubRows(), element, gen, corePath, profileBaseFileName, mustSupport);
}
}
return slicingRow;
@ -3967,7 +4023,7 @@ public class ProfileUtilities extends TranslatingUtilities {
res.add(genCardinality(gen, element, row, hasDef, used, extDefn.getElement()));
ElementDefinition valueDefn = extDefn.getExtensionValueDefinition();
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
// 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)));
@ -3978,7 +4034,7 @@ public class ProfileUtilities extends TranslatingUtilities {
if ("0".equals(element.getMax()))
res.add(addCell(row, gen.new Cell()));
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));
}
} else {
@ -3986,7 +4042,7 @@ public class ProfileUtilities extends TranslatingUtilities {
if (element.hasSlicing())
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)
res.add(genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root));
res.add(genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root, mustSupport));
else
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));
@ -4048,96 +4104,101 @@ public class ProfileUtilities extends TranslatingUtilities {
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
for (TypeRefComponent tr : element.getType()) {
Row choicerow = gen.new Row();
String t = tr.getWorkingCode();
if (isReference(t)) {
choicerow.getCells().add(gen.new Cell(null, null, tail(element.getPath()).replace("[x]", Utilities.capitalize(t)), null, null));
choicerow.getCells().add(gen.new Cell());
choicerow.getCells().add(gen.new Cell(null, null, "", null, null));
choicerow.setIcon("icon_reference.png", HierarchicalTableGenerator.TEXT_ICON_REFERENCE);
Cell c = gen.new Cell();
choicerow.getCells().add(c);
if (ADD_REFERENCE_TO_TABLE) {
if (tr.getWorkingCode().equals("canonical"))
c.getPieces().add(gen.new Piece(corePath+"datatypes.html#canonical", "canonical", null));
else
c.getPieces().add(gen.new Piece(corePath+"references.html#Reference", "Reference", null));
if (isMustSupportDirect(tr) && element.getMustSupport()) {
c.addPiece(gen.new Piece(null, " ", null));
c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false);
}
c.getPieces().add(gen.new Piece(null, "(", null));
}
boolean first = true;
for (CanonicalType rt : tr.getTargetProfile()) {
if (!first)
c.getPieces().add(gen.new Piece(null, " | ", null));
genTargetLink(gen, profileBaseFileName, corePath, c, tr, rt.getValue());
if (isMustSupport(rt) && element.getMustSupport()) {
c.addPiece(gen.new Piece(null, " ", null));
c.addStyledText(translate("sd.table", "This target must be supported"), "S", "white", "red", null, false);
}
first = false;
}
if (first)
c.getPieces().add(gen.new Piece(null, "Any", null));
if (ADD_REFERENCE_TO_TABLE)
c.getPieces().add(gen.new Piece(null, ")", null));
} else {
StructureDefinition sd = context.fetchTypeDefinition(t);
if (sd == null) {
System.out.println("Unable to find "+t);
sd = context.fetchTypeDefinition(t);
} else if (sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE) {
choicerow.getCells().add(gen.new Cell(null, null, tail(element.getPath()).replace("[x]", Utilities.capitalize(t)), sd.getDescription(), null));
if (!mustSupportMode || allTypesMustSupport(element) || isMustSupport(tr)) {
Row choicerow = gen.new Row();
String t = tr.getWorkingCode();
if (isReference(t)) {
choicerow.getCells().add(gen.new Cell(null, null, tail(element.getPath()).replace("[x]", Utilities.capitalize(t)), null, null));
choicerow.getCells().add(gen.new Cell());
choicerow.getCells().add(gen.new Cell(null, null, "", null, null));
choicerow.setIcon("icon_primitive.png", HierarchicalTableGenerator.TEXT_ICON_PRIMITIVE);
Cell c = gen.new Cell(null, corePath+"datatypes.html#"+t, sd.getType(), null, null);
choicerow.setIcon("icon_reference.png", HierarchicalTableGenerator.TEXT_ICON_REFERENCE);
Cell c = gen.new Cell();
choicerow.getCells().add(c);
if (isMustSupport(tr) && element.getMustSupport()) {
c.addPiece(gen.new Piece(null, " ", null));
c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false);
}
} else {
choicerow.getCells().add(gen.new Cell(null, null, tail(element.getPath()).replace("[x]", Utilities.capitalize(t)), sd.getDescription(), null));
choicerow.getCells().add(gen.new Cell());
choicerow.getCells().add(gen.new Cell(null, null, "", null, null));
choicerow.setIcon("icon_datatype.gif", HierarchicalTableGenerator.TEXT_ICON_DATATYPE);
Cell c = gen.new Cell(null, pkp.getLinkFor(corePath, t), sd.getType(), null, null);
choicerow.getCells().add(c);
if (isMustSupport(tr) && element.getMustSupport()) {
c.addPiece(gen.new Piece(null, " ", null));
c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false);
}
}
if (tr.hasProfile()) {
Cell typeCell = choicerow.getCells().get(3);
typeCell.addPiece(gen.new Piece(null, "(", null));
boolean first = true;
for (CanonicalType pt : tr.getProfile()) {
if (first) first = false; else typeCell.addPiece(gen.new Piece(null, " | ", null));
StructureDefinition psd = context.fetchResource(StructureDefinition.class, pt.getValue());
if (psd == null)
typeCell.addPiece(gen.new Piece(null, "?gen-e2?", null));
if (ADD_REFERENCE_TO_TABLE) {
if (tr.getWorkingCode().equals("canonical"))
c.getPieces().add(gen.new Piece(corePath+"datatypes.html#canonical", "canonical", null));
else
typeCell.addPiece(gen.new Piece(psd.getUserString("path"), psd.getName(), psd.present()));
if (isMustSupport(pt) && element.getMustSupport()) {
typeCell.addPiece(gen.new Piece(null, " ", null));
typeCell.addStyledText(translate("sd.table", "This profile must be supported"), "S", "white", "red", null, false);
c.getPieces().add(gen.new Piece(corePath+"references.html#Reference", "Reference", null));
if (!mustSupportMode && isMustSupportDirect(tr) && element.getMustSupport()) {
c.addPiece(gen.new Piece(null, " ", null));
c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false);
}
c.getPieces().add(gen.new Piece(null, "(", null));
}
typeCell.addPiece(gen.new Piece(null, ")", null));
}
}
choicerow.getCells().add(gen.new Cell());
subRows.add(choicerow);
boolean first = true;
for (CanonicalType rt : tr.getTargetProfile()) {
if (!mustSupportMode || allProfilesMustSupport(tr.getTargetProfile()) || isMustSupport(rt)) {
if (!first)
c.getPieces().add(gen.new Piece(null, " | ", null));
genTargetLink(gen, profileBaseFileName, corePath, c, tr, rt.getValue());
if (!mustSupportMode && isMustSupport(rt) && element.getMustSupport()) {
c.addPiece(gen.new Piece(null, " ", null));
c.addStyledText(translate("sd.table", "This target must be supported"), "S", "white", "red", null, false);
}
first = false;
}
}
if (first)
c.getPieces().add(gen.new Piece(null, "Any", null));
if (ADD_REFERENCE_TO_TABLE)
c.getPieces().add(gen.new Piece(null, ")", null));
} else {
StructureDefinition sd = context.fetchTypeDefinition(t);
if (sd == null) {
System.out.println("Unable to find "+t);
sd = context.fetchTypeDefinition(t);
} else if (sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE) {
choicerow.getCells().add(gen.new Cell(null, null, tail(element.getPath()).replace("[x]", Utilities.capitalize(t)), sd.getDescription(), null));
choicerow.getCells().add(gen.new Cell());
choicerow.getCells().add(gen.new Cell(null, null, "", null, null));
choicerow.setIcon("icon_primitive.png", HierarchicalTableGenerator.TEXT_ICON_PRIMITIVE);
Cell c = gen.new Cell(null, corePath+"datatypes.html#"+t, sd.getType(), null, null);
choicerow.getCells().add(c);
if (!mustSupportMode && isMustSupport(tr) && element.getMustSupport()) {
c.addPiece(gen.new Piece(null, " ", null));
c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false);
}
} else {
choicerow.getCells().add(gen.new Cell(null, null, tail(element.getPath()).replace("[x]", Utilities.capitalize(t)), sd.getDescription(), null));
choicerow.getCells().add(gen.new Cell());
choicerow.getCells().add(gen.new Cell(null, null, "", null, null));
choicerow.setIcon("icon_datatype.gif", HierarchicalTableGenerator.TEXT_ICON_DATATYPE);
Cell c = gen.new Cell(null, pkp.getLinkFor(corePath, t), sd.getType(), null, null);
choicerow.getCells().add(c);
if (!mustSupportMode && isMustSupport(tr) && element.getMustSupport()) {
c.addPiece(gen.new Piece(null, " ", null));
c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false);
}
}
if (tr.hasProfile()) {
Cell typeCell = choicerow.getCells().get(3);
typeCell.addPiece(gen.new Piece(null, "(", null));
boolean first = true;
for (CanonicalType pt : tr.getProfile()) {
if (!mustSupportMode || allProfilesMustSupport(tr.getProfile()) || isMustSupport(pt)) {
if (first) first = false; else typeCell.addPiece(gen.new Piece(null, " | ", null));
StructureDefinition psd = context.fetchResource(StructureDefinition.class, pt.getValue());
if (psd == null)
typeCell.addPiece(gen.new Piece(null, "?gen-e2?", null));
else
typeCell.addPiece(gen.new Piece(psd.getUserString("path"), psd.getName(), psd.present()));
if (!mustSupportMode && isMustSupport(pt) && element.getMustSupport()) {
typeCell.addPiece(gen.new Piece(null, " ", null));
typeCell.addStyledText(translate("sd.table", "This profile must be supported"), "S", "white", "red", null, false);
}
}
}
typeCell.addPiece(gen.new Piece(null, ")", null));
}
}
choicerow.getCells().add(gen.new Cell());
subRows.add(choicerow);
}
}
}
@ -4182,7 +4243,7 @@ public class ProfileUtilities extends TranslatingUtilities {
ExtensionContext extDefn = null;
genCardinality(gen, element, row, hasDef, used, null);
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
row.getCells().add(gen.new Cell());
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))) {
actual = base+(ref.substring(1)+"."+path.substring(p.length()+1)).substring(prefixLength);
path = actual;
} else if (ref.startsWith("http:")) {
actual = base+(ref.substring(ref.indexOf("#")+1)+"."+path.substring(p.length()+1)).substring(prefixLength);
path = actual;
} else {
// 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);
@ -6365,6 +6429,25 @@ public class ProfileUtilities extends TranslatingUtilities {
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) {
return ("true".equals(ToolingExtensions.readStringExtension(tr, ToolingExtensions.EXT_MUST_SUPPORT)));
}

View File

@ -142,7 +142,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer {
rows.add(r);
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));
String txt = (i.hasPrefix() ? i.getPrefix() + ". " : "") + i.getText();
r.getCells().add(gen.new Cell(null, null, txt, null, null));
@ -361,7 +361,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer {
rows.add(r);
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));
Cell defn = gen.new Cell();
r.getCells().add(defn);

View File

@ -523,14 +523,13 @@ public class ValueSetCheckerSimple implements ValueSetChecker {
} else {
if (vsi.hasFilter()) {
boolean ok = true;
for (ConceptSetFilterComponent f : vsi.getFilter())
for (ConceptSetFilterComponent f : vsi.getFilter()) {
if (!codeInFilter(cs, system, f, code)) {
ok = false;
break;
}
if (ok) {
return true;
}
return ok;
}
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.VersionUtilities;
import org.hl7.fhir.utilities.json.JSONUtil;
import org.hl7.fhir.utilities.json.JsonTrackingParser;
import org.hl7.fhir.utilities.npm.NpmPackage.NpmPackageFolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -549,7 +550,9 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
@Override
public String getPackageId(String canonicalUrl) throws IOException {
String retVal = super.getPackageId(canonicalUrl);
String retVal = findCanonicalInLocalCache(canonicalUrl);
retVal = super.getPackageId(canonicalUrl);
if (retVal == null) {
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 =======================================================================
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;
}
private BasePackageCacheManager pcm;
private FilesystemPackageCacheManager pcm;
private IWorkerContext context;
private IPackageInstaller installer;
@ -51,19 +51,37 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher {
if (!Utilities.isAbsoluteUrl(url)) {
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
// first possibility: it's a reference to a version specific URL http://hl7.org/fhir/X.X/...
VersionURLInfo vu = VersionUtilities.parseVersionUrl(url);
if (vu != null) {
NpmPackage pi = pcm.loadPackage(VersionUtilities.packageForVersion(vu.getVersion()), VersionUtilities.getCurrentVersion(vu.getVersion()));
return pi.hasCanonical(vu.getUrl());
// 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/...
VersionURLInfo vu = VersionUtilities.parseVersionUrl(url);
if (vu != null) {
NpmPackage pi = pcm.loadPackage(VersionUtilities.packageForVersion(vu.getVersion()), VersionUtilities.getCurrentVersion(vu.getVersion()));
return pi.hasCanonical(vu.getUrl());
}
}
// 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 (installer.packageExists(pid, ver)) {
installer.loadPackage(pid, ver);
@ -72,13 +90,8 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher {
}
}
if (!url.startsWith("http://hl7.org/fhir")) {
return true; // we don't bother with those in the standalone validator - we assume they are valid
}
// we assume it's invalid at this point
return false;
// we don't bother with urls outside fhir space in the standalone validator - we assume they are valid
return !url.startsWith("http://hl7.org/fhir");
}
private String findBaseUrl(String url) {

View File

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

View File

@ -19,7 +19,7 @@
<properties>
<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>
<maven_surefire_version>3.0.0-M4</maven_surefire_version>
<jacoco_version>0.8.5</jacoco_version>