diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/analytics/PackageVisitor.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/analytics/PackageVisitor.java index e04734fbe..fba153415 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/analytics/PackageVisitor.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/analytics/PackageVisitor.java @@ -33,9 +33,34 @@ import org.w3c.dom.Element; import org.xml.sax.SAXException; public class PackageVisitor { + + public static class PackageContext { + private String pid; + private NpmPackage npm; + private String version; + protected PackageContext(String pid, NpmPackage npm, String version) { + super(); + this.pid = pid; + this.npm = npm; + this.version = version; + } + public String getPid() { + return pid; + } + public NpmPackage getNpm() { + return npm; + } + public String getVersion() { + return version; + } + } public interface IPackageVisitorProcessor { - public void processResource(String pid, NpmPackage npm, String version, String type, String id, byte[] content) throws FHIRException, IOException, EOperationOutcome; + public Object startPackage(PackageContext context) throws FHIRException, IOException, EOperationOutcome; + public void processResource(PackageContext context, Object clientContext, String type, String id, byte[] content) throws FHIRException, IOException, EOperationOutcome; + public void finishPackage(PackageContext context) throws FHIRException, IOException, EOperationOutcome; + + public void alreadyVisited(String pid) throws FHIRException, IOException, EOperationOutcome; } private List resourceTypes = new ArrayList<>(); @@ -47,7 +72,7 @@ public class PackageVisitor { private FilesystemPackageCacheManager pcm; private PackageClient pc; private String cache; - + public List getResourceTypes() { return resourceTypes; } @@ -117,13 +142,13 @@ public class PackageVisitor { this.processor = processor; } - public void visitPackages() throws IOException, ParserConfigurationException, SAXException { + public void visitPackages() throws IOException, ParserConfigurationException, SAXException, FHIRException, EOperationOutcome { System.out.println("Finding packages"); pc = new PackageClient(PackageServer.primaryServer()); pcm = new FilesystemPackageCacheManager(org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager.FilesystemPackageCacheMode.USER); - + Set pidList = getAllPackages(); - + Map cpidMap = getAllCIPackages(); Set cpidSet = new HashSet<>(); System.out.println("Go: "+cpidMap.size()+" current packages"); @@ -132,7 +157,7 @@ public class PackageVisitor { processCurrentPackage(s, cpidMap.get(s), cpidSet, i, cpidMap.size()); i++; } - + System.out.println("Go: "+pidList.size()+" published packages"); i = 0; for (String pid : pidList) { @@ -149,6 +174,8 @@ public class PackageVisitor { } else { processPackage(pid, vList.get(vList.size() - 1), i, pidList.size()); } + } else { + processor.alreadyVisited(pid); } i++; } @@ -192,22 +219,35 @@ public class PackageVisitor { String fv = npm.fhirVersion(); cpidSet.add(pid); long ms2 = System.currentTimeMillis(); - + if (corePackages || !corePackage(npm)) { if (fv != null && (versions.isEmpty() || versions.contains(fv))) { - int c = 0; - for (String type : resourceTypes) { - for (String s : npm.listResources(type)) { - c++; - try { - processor.processResource(pid+"#current", npm, fv, type, s, TextFile.streamToBytes(npm.load("package", s))); - } catch (Exception e) { - System.out.println("####### Error loading "+pid+"#current["+fv+"]/"+type+" ####### "+e.getMessage()); -// e.printStackTrace(); + PackageContext ctxt = new PackageContext(pid+"#current", npm, fv); + boolean ok = false; + Object context = null; + try { + context = processor.startPackage(ctxt); + ok = true; + } catch (Exception e) { + System.out.println("####### Error loading "+pid+"#current["+fv+"]: ####### "+e.getMessage()); + // e.printStackTrace(); + } + if (ok) { + int c = 0; + for (String type : resourceTypes) { + for (String s : npm.listResources(type)) { + c++; + try { + processor.processResource(ctxt, context, type, s, TextFile.streamToBytes(npm.load("package", s))); + } catch (Exception e) { + System.out.println("####### Error loading "+pid+"#current["+fv+"]/"+type+" ####### "+e.getMessage()); + // e.printStackTrace(); + } } } + processor.finishPackage(ctxt); + System.out.println("Processed: "+pid+"#current: "+c+" resources ("+i+" of "+t+", "+(ms2-ms1)+"/"+(System.currentTimeMillis()-ms2)+"ms)"); } - System.out.println("Processed: "+pid+"#current: "+c+" resources ("+i+" of "+t+", "+(ms2-ms1)+"/"+(System.currentTimeMillis()-ms2)+"ms)"); } else { System.out.println("Ignored: "+pid+"#current: no version"); } @@ -252,7 +292,7 @@ public class PackageVisitor { for (JsonObject feed : json.getJsonObjects("feeds")) { processFeed(list, feed.asString("url")); } - + return list; } @@ -277,7 +317,7 @@ public class PackageVisitor { } - private void processPackage(String pid, String v, int i, int t) throws IOException { + private void processPackage(String pid, String v, int i, int t) throws IOException, FHIRException, EOperationOutcome { NpmPackage npm = null; String fv = null; try { @@ -287,21 +327,34 @@ public class PackageVisitor { System.out.println("Unable to process: "+pid+"#"+v+": "+e.getMessage()); } if (corePackages || !corePackage(npm)) { - int c = 0; - if (fv != null && (versions.isEmpty() || versions.contains(fv))) { - for (String type : resourceTypes) { - for (String s : npm.listResources(type)) { - c++; - try { - processor.processResource(pid+"#"+v, npm, fv, type, s, TextFile.streamToBytes(npm.load("package", s))); - } catch (Exception e) { - System.out.println("####### Error loading "+pid+"#"+v +"["+fv+"]/"+type+" ####### "+e.getMessage()); - e.printStackTrace(); + PackageContext ctxt = new PackageContext(pid+"#"+v, npm, fv); + boolean ok = false; + Object context = null; + try { + context = processor.startPackage(ctxt); + ok = true; + } catch (Exception e) { + System.out.println("####### Error loading package "+pid+"#"+v +"["+fv+"]: "+e.getMessage()); + e.printStackTrace(); + } + if (ok) { + int c = 0; + if (fv != null && (versions.isEmpty() || versions.contains(fv))) { + for (String type : resourceTypes) { + for (String s : npm.listResources(type)) { + c++; + try { + processor.processResource(ctxt, context, type, s, TextFile.streamToBytes(npm.load("package", s))); + } catch (Exception e) { + System.out.println("####### Error loading "+pid+"#"+v +"["+fv+"]/"+type+" ####### "+e.getMessage()); + e.printStackTrace(); + } } } - } - } - System.out.println("Processed: "+pid+"#"+v+": "+c+" resources ("+i+" of "+t+")"); + } + processor.finishPackage(ctxt); + System.out.println("Processed: "+pid+"#"+v+": "+c+" resources ("+i+" of "+t+")"); + } } } diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/analytics/SearchParameterAnalysis.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/analytics/SearchParameterAnalysis.java index 961c178a0..8fc803eb1 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/analytics/SearchParameterAnalysis.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/analytics/SearchParameterAnalysis.java @@ -12,8 +12,10 @@ import java.util.Set; import javax.xml.parsers.ParserConfigurationException; import org.hl7.fhir.convertors.analytics.PackageVisitor.IPackageVisitorProcessor; +import org.hl7.fhir.convertors.analytics.PackageVisitor.PackageContext; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRFormatError; +import org.hl7.fhir.r5.utils.EOperationOutcome; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.npm.NpmPackage; @@ -89,17 +91,29 @@ public class SearchParameterAnalysis implements IPackageVisitorProcessor { } } System.out.println(); - } - + } } } private Map versions = new HashMap(); + @Override - public void processResource(String pid, NpmPackage npm, String version, String type, String id, byte[] content) throws FHIRException { -// System.out.println("v"+version+" "+type+" from "+pid); + public void alreadyVisited(String pid) { + + } + + @Override + public Object startPackage(PackageContext ctxt) { + return null; + } + + @Override + public void processResource(PackageContext ctxt, Object context, String type, String id, byte[] content) throws FHIRException, IOException, EOperationOutcome { +// System.out.println("v"+version+" "+type+" from "+pid); + String pid = ctxt.getPid(); + String version = ctxt.getVersion(); boolean core = pid.startsWith("hl7.fhir.r") && (pid.contains(".core") || pid.contains(".examples")); version = VersionUtilities.getMajMin(version); if (!versions.containsKey(version)) { @@ -123,6 +137,11 @@ public class SearchParameterAnalysis implements IPackageVisitorProcessor { } } + @Override + public void finishPackage(PackageContext ctxt) { + + } + private void processR5SP(boolean core, SearchParameterVersionAnalysis analysis, byte[] content) throws FHIRFormatError, IOException { org.hl7.fhir.r5.model.Resource res = new org.hl7.fhir.r5.formats.JsonParser().parse(content); if (res instanceof org.hl7.fhir.r5.model.Bundle) { @@ -187,7 +206,7 @@ public class SearchParameterAnalysis implements IPackageVisitorProcessor { new SearchParameterAnalysis().execute(); } - private void execute() throws IOException, ParserConfigurationException, SAXException { + private void execute() throws IOException, ParserConfigurationException, SAXException, FHIRException, EOperationOutcome { PackageVisitor pv = new PackageVisitor(); pv.getResourceTypes().add("SearchParameter"); pv.getResourceTypes().add("Bundle"); @@ -207,4 +226,5 @@ public class SearchParameterAnalysis implements IPackageVisitorProcessor { } } + } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java index 324ec0546..dd2ec8995 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java @@ -2467,10 +2467,12 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte @Override public StructureDefinition fetchTypeDefinition(String typeName) { if (Utilities.isAbsoluteUrl(typeName)) { - return fetchResource(StructureDefinition.class, typeName); - } else { - return typeManager.fetchTypeDefinition(typeName); - } + StructureDefinition res = fetchResource(StructureDefinition.class, typeName); + if (res != null) { + return res; + } + } + return typeManager.fetchTypeDefinition(typeName); } @Override diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Element.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Element.java index 5bf66f08b..9d0cae21b 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Element.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Element.java @@ -38,6 +38,7 @@ import org.apache.commons.lang3.Validate; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; import org.hl7.fhir.r5.context.ContextUtilities; +import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat; import org.hl7.fhir.r5.extensions.ExtensionsUtils; import org.hl7.fhir.r5.model.Base; import org.hl7.fhir.r5.model.DataType; @@ -130,6 +131,7 @@ public class Element extends Base implements NamedItem { private boolean isNull; private Base source; private boolean ignorePropertyOrder; + private FhirFormat format; public Element(String name) { super(); @@ -421,7 +423,7 @@ public class Element extends Base implements NamedItem { childForValue = child; break; } else { - Element ne = new Element(child); + Element ne = new Element(child).setFormat(format); children.add(ne); numberChildren(); childForValue = ne; @@ -442,7 +444,7 @@ public class Element extends Base implements NamedItem { if (t >= i) i = t+1; if (p.getName().equals(name) || p.getName().equals(name+"[x]")) { - Element ne = new Element(name, p); + Element ne = new Element(name, p).setFormat(format); children.add(i, ne); childForValue = ne; break; @@ -504,7 +506,7 @@ public class Element extends Base implements NamedItem { if (!child.isList()) { return child; } else { - Element ne = new Element(child); + Element ne = new Element(child).setFormat(format); children.add(ne); numberChildren(); return ne; @@ -514,7 +516,7 @@ public class Element extends Base implements NamedItem { for (Property p : property.getChildProperties(this.name, type)) { if (p.getName().equals(name)) { - Element ne = new Element(name, p); + Element ne = new Element(name, p).setFormat(format); children.add(ne); return ne; } else if (p.getDefinition().isChoice() && name.startsWith(p.getName().replace("[x]", ""))) { @@ -522,7 +524,7 @@ public class Element extends Base implements NamedItem { if (property.getContext().isPrimitiveType(Utilities.uncapitalize(type))) { type = Utilities.uncapitalize(type); } - Element ne = new Element(name, p); + Element ne = new Element(name, p).setFormat(format); ne.setType(type); children.add(ne); return ne; @@ -546,7 +548,7 @@ public class Element extends Base implements NamedItem { for (Property p : property.getChildProperties(this.name, type)) { if (p.getName().equals(name)) { - Element ne = new Element(name, p); + Element ne = new Element(name, p).setFormat(format); children.add(ne); return ne; } @@ -1295,7 +1297,7 @@ public class Element extends Base implements NamedItem { if (!p.isList() && hasChild(name)) { throw new Error(name+" on "+this.name+" is not a list, so can't add an element"); } - Element ne = new Element(name, p); + Element ne = new Element(name, p).setFormat(format); children.add(ne); return ne; } @@ -1344,6 +1346,7 @@ public class Element extends Base implements NamedItem { dest.instanceId = instanceId; dest.isNull = isNull; dest.source = source; + dest.format = format; } public Base setProperty(String name, Base value) throws FHIRException { @@ -1466,4 +1469,13 @@ public class Element extends Base implements NamedItem { } } + public FhirFormat getFormat() { + return format; + } + + public Element setFormat(FhirFormat format) { + this.format = format; + return this; + } + } \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java index 0ad5cf39c..2360f7f80 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java @@ -52,6 +52,7 @@ import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; import org.hl7.fhir.r5.context.ContextUtilities; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.elementmodel.Element.SpecialElement; +import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat; import org.hl7.fhir.r5.formats.IParser.OutputStyle; import org.hl7.fhir.r5.formats.JsonCreator; import org.hl7.fhir.r5.formats.JsonCreatorCanonical; @@ -108,7 +109,7 @@ public class JsonParser extends ParserBase { // if (sd == null) // return null; // -// Element result = new Element(type, new Property(context, sd.getSnapshot().getElement().get(0), sd, this.profileUtilities)); +// Element result = new Element(type, new Property(context, sd.getSnapshot().getElement().get(0), sd, this.profileUtilities)).setFormat(FhirFormat.JSON); // result.setPath(type); // checkObject(obj, result, path); // result.setType(type); @@ -179,7 +180,7 @@ public class JsonParser extends ParserBase { name = sd.getType(); path = sd.getTypeTail(); } - baseElement = new Element(name, new Property(context, sd.getSnapshot().getElement().get(0), sd, this.profileUtilities)); + baseElement = new Element(name, new Property(context, sd.getSnapshot().getElement().get(0), sd, this.profileUtilities)).setFormat(FhirFormat.JSON); checkObject(errors, object, baseElement, path); baseElement.markLocation(line(object), col(object)); baseElement.setType(name); @@ -433,12 +434,12 @@ public class JsonParser extends ParserBase { String npathArr = path+"."+property.getName()+"["+i+"]"; String fpathArr = element.getPath()+"."+property.getName()+"["+i+"]"; - Element n = new Element(name, property).markLocation(line(pv.getValue()), col(pv.getValue())); + Element n = new Element(name, property).markLocation(line(pv.getValue()), col(pv.getValue())).setFormat(FhirFormat.JSON); n.setPath(fpath); element.getChildren().add(n); // handle the key String fpathKey = fpathArr+"."+propK.getName(); - Element nKey = new Element(code, propK).markLocation(line(pv.getValue()), col(pv.getValue())); + Element nKey = new Element(code, propK).markLocation(line(pv.getValue()), col(pv.getValue())).setFormat(FhirFormat.JSON); checkComments(errors, pv.getValue(), n, fpathArr); nKey.setPath(fpathKey); n.getChildren().add(nKey); @@ -524,7 +525,7 @@ public class JsonParser extends ParserBase { } if (e instanceof JsonObject) { JsonObject child = (JsonObject) e; - Element n = new Element(name, property).markLocation(line(child), col(child)); + Element n = new Element(name, property).markLocation(line(child), col(child)).setFormat(FhirFormat.JSON); n.setPath(fpath); checkComments(errors, commentContext, n, commentPath); checkObject(errors, child, n, npath); @@ -537,7 +538,7 @@ public class JsonParser extends ParserBase { } else if (property.isNullable() && e instanceof JsonNull) { // we create an element marked as a null element so we know something was present JsonNull child = (JsonNull) e; - Element n = new Element(name, property).markLocation(line(child), col(child)); + Element n = new Element(name, property).markLocation(line(child), col(child)).setFormat(FhirFormat.JSON); checkComments(errors, commentContext, n, commentPath); checkComments(errors, child, n, fpath); n.setPath(fpath); @@ -632,7 +633,7 @@ public class JsonParser extends ParserBase { } else if (fork != null && !(fork instanceof JsonObject)) { logError(errors, ValidationMessage.NO_RULE_DATE, line(fork), col(fork), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_PROPERTY_MUST_BE_AN_OBJECT_NOT_, describe(fork), name, npath), IssueSeverity.ERROR); } else { - Element n = new Element(isJsonName ? property.getName() : name, property).markLocation(line(main != null ? main : fork), col(main != null ? main : fork)); + Element n = new Element(isJsonName ? property.getName() : name, property).markLocation(line(main != null ? main : fork), col(main != null ? main : fork)).setFormat(FhirFormat.JSON); if (main != null) { checkComments(errors, main, n, npath); } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/TurtleParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/TurtleParser.java index 54c7a4f19..94c5a427f 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/TurtleParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/TurtleParser.java @@ -45,6 +45,7 @@ import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.elementmodel.Element.SpecialElement; +import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat; import org.hl7.fhir.r5.formats.IParser.OutputStyle; import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent; import org.hl7.fhir.r5.model.StructureDefinition; @@ -150,7 +151,7 @@ public class TurtleParser extends ParserBase { if (sd == null) return null; - Element result = new Element(name, new Property(context, sd.getSnapshot().getElement().get(0), sd)); + Element result = new Element(name, new Property(context, sd.getSnapshot().getElement().get(0), sd)).setFormat(FhirFormat.TURTLE); result.markLocation(cmp.getLine(), cmp.getCol()); result.setType(name); parseChildren(errors, src, path, cmp, result, false); @@ -210,7 +211,7 @@ public class TurtleParser extends ParserBase { parseResource(errors, src, npath, object, element, property, name, e); else if (e instanceof TTLComplex) { TTLComplex child = (TTLComplex) e; - Element n = new Element(tail(name), property).markLocation(e.getLine(), e.getCol()); + Element n = new Element(tail(name), property).markLocation(e.getLine(), e.getCol()).setFormat(FhirFormat.TURTLE); element.getChildren().add(n); if (property.isPrimitive(property.getType(tail(name)))) { parseChildren(errors, src, npath, child, n, true); @@ -276,7 +277,7 @@ public class TurtleParser extends ParserBase { if (sd == null) return; - Element n = new Element(tail(name), property).markLocation(object.getLine(), object.getCol()); + Element n = new Element(tail(name), property).markLocation(object.getLine(), object.getCol()).setFormat(FhirFormat.TURTLE); element.getChildren().add(n); n.updateProperty(new Property(this.context, sd.getSnapshot().getElement().get(0), sd), SpecialElement.fromProperty(n.getProperty()), property); n.setType(rt); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/XmlParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/XmlParser.java index 2ed10d15b..c6ca214cf 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/XmlParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/XmlParser.java @@ -57,6 +57,7 @@ import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.elementmodel.Element.SpecialElement; +import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat; import org.hl7.fhir.r5.formats.FormatUtilities; import org.hl7.fhir.r5.formats.IParser.OutputStyle; import org.hl7.fhir.r5.model.DateTimeType; @@ -228,7 +229,7 @@ public class XmlParser extends ParserBase { if (sd == null) return null; - Element result = new Element(element.getLocalName(), new Property(context, sd.getSnapshot().getElement().get(0), sd)); + Element result = new Element(element.getLocalName(), new Property(context, sd.getSnapshot().getElement().get(0), sd)).setFormat(FhirFormat.XML); result.setPath(element.getLocalName()); checkElement(errors, element, path, result.getProperty()); result.markLocation(line(element, false), col(element, false)); @@ -288,7 +289,7 @@ public class XmlParser extends ParserBase { public Element parse(List errors, org.w3c.dom.Element base, String type) throws Exception { StructureDefinition sd = getDefinition(errors, 0, 0, FormatUtilities.FHIR_NS, type); - Element result = new Element(base.getLocalName(), new Property(context, sd.getSnapshot().getElement().get(0), sd)); + Element result = new Element(base.getLocalName(), new Property(context, sd.getSnapshot().getElement().get(0), sd)).setFormat(FhirFormat.XML); result.setPath(base.getLocalName()); String path = "/"+pathPrefix(base.getNamespaceURI())+base.getLocalName(); checkElement(errors, base, path, result.getProperty()); @@ -311,16 +312,16 @@ public class XmlParser extends ParserBase { if (property != null) { if ("ED.data[x]".equals(property.getDefinition().getId()) || (property.getDefinition()!=null && property.getDefinition().getBase()!=null && "ED.data[x]".equals(property.getDefinition().getBase().getPath()))) { if ("B64".equals(node.getAttribute("representation"))) { - Element n = new Element("dataBase64Binary", property, "base64Binary", text).markLocation(line, col); + Element n = new Element("dataBase64Binary", property, "base64Binary", text).markLocation(line, col).setFormat(FhirFormat.XML); n.setPath(element.getPath()+"."+property.getName()); element.getChildren().add(n); } else { - Element n = new Element("dataString", property, "string", text).markLocation(line, col); + Element n = new Element("dataString", property, "string", text).markLocation(line, col).setFormat(FhirFormat.XML); n.setPath(element.getPath()+"."+property.getName()); element.getChildren().add(n); } } else { - Element n = new Element(property.getName(), property, property.getType(), text).markLocation(line, col); + Element n = new Element(property.getName(), property, property.getType(), text).markLocation(line, col).setFormat(FhirFormat.XML); n.setPath(element.getPath()+"."+property.getName()); element.getChildren().add(n); } @@ -368,7 +369,7 @@ public class XmlParser extends ParserBase { vl = av.split(" "); } for (String v : vl) { - Element n = new Element(property.getName(), property, property.getType(), v).markLocation(line, col); + Element n = new Element(property.getName(), property, property.getType(), v).markLocation(line, col).setFormat(FhirFormat.XML); n.setPath(element.getPath()+"."+property.getName()); element.getChildren().add(n); } @@ -415,12 +416,12 @@ public class XmlParser extends ParserBase { } } } - Element n = new Element(property.getName(), property, "xhtml", new XhtmlComposer(XhtmlComposer.XML, false).compose(xhtml)).setXhtml(xhtml).markLocation(line(child, false), col(child, false)); + Element n = new Element(property.getName(), property, "xhtml", new XhtmlComposer(XhtmlComposer.XML, false).compose(xhtml)).setXhtml(xhtml).markLocation(line(child, false), col(child, false)).setFormat(FhirFormat.XML); n.setPath(element.getPath()+"."+property.getName()); element.getChildren().add(n); } else { String npath = path+"/"+pathPrefix(child.getNamespaceURI())+child.getLocalName(); - Element n = new Element(child.getLocalName(), property).markLocation(line(child, false), col(child, false)); + Element n = new Element(child.getLocalName(), property).markLocation(line(child, false), col(child, false)).setFormat(FhirFormat.XML); if (property.isList()) { n.setPath(element.getPath()+"."+property.getName()+"["+repeatCount+"]"); } else { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java index 0212eb891..5d2cd4ec5 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java @@ -5794,7 +5794,10 @@ public class FHIRPathEngine { url = type; } String tail = ""; - StructureDefinition sd = worker.fetchResource(StructureDefinition.class, url); + StructureDefinition sd = worker.fetchTypeDefinition(url); + if (sd == null) { + sd = worker.fetchResource(StructureDefinition.class, url); + } if (sd == null) { if (url.startsWith(TypeDetails.FP_NS)) { return; diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java index 5d9da1fac..6cf99660b 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java @@ -100,7 +100,7 @@ import org.hl7.fhir.validation.cli.utils.QuestionnaireMode; import org.hl7.fhir.validation.cli.utils.SchemaValidator; import org.hl7.fhir.validation.cli.utils.ValidationLevel; import org.hl7.fhir.validation.instance.InstanceValidator; -import org.hl7.fhir.validation.instance.utils.ValidatorHostContext; +import org.hl7.fhir.validation.instance.utils.ValidationContext; import org.hl7.fhir.utilities.ByteProvider; import org.xml.sax.SAXException; @@ -796,7 +796,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP FHIRPathEngine fpe = this.getValidator(null).getFHIRPathEngine(); Element e = Manager.parseSingle(context, new ByteArrayInputStream(cnt.getFocus().getBytes()), cnt.getCntType()); ExpressionNode exp = fpe.parse(expression); - return fpe.evaluateToString(new ValidatorHostContext(context, e), e, e, e, exp); + return fpe.evaluateToString(new ValidationContext(context, e), e, e, e, exp); } public StructureDefinition snapshot(String source, String version) throws FHIRException, IOException { diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java index 317f8e61c..d31e8a388 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java @@ -46,7 +46,6 @@ import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -208,14 +207,18 @@ import org.hl7.fhir.validation.instance.type.StructureMapValidator; import org.hl7.fhir.validation.instance.type.StructureMapValidator.VariableDefn; import org.hl7.fhir.validation.instance.type.StructureMapValidator.VariableSet; import org.hl7.fhir.validation.instance.type.ValueSetValidator; +import org.hl7.fhir.validation.instance.utils.CanonicalResourceLookupResult; +import org.hl7.fhir.validation.instance.utils.CanonicalTypeSorter; import org.hl7.fhir.validation.instance.utils.ChildIterator; import org.hl7.fhir.validation.instance.utils.ElementInfo; +import org.hl7.fhir.validation.instance.utils.EnableWhenEvaluator; import org.hl7.fhir.validation.instance.utils.FHIRPathExpressionFixer; import org.hl7.fhir.validation.instance.utils.IndexedElement; import org.hl7.fhir.validation.instance.utils.NodeStack; import org.hl7.fhir.validation.instance.utils.ResolvedReference; import org.hl7.fhir.validation.instance.utils.ResourceValidationTracker; -import org.hl7.fhir.validation.instance.utils.ValidatorHostContext; +import org.hl7.fhir.validation.instance.utils.StructureDefinitionSorterByUrl; +import org.hl7.fhir.validation.instance.utils.ValidationContext; import org.w3c.dom.Document; /** @@ -236,38 +239,6 @@ import org.w3c.dom.Document; public class InstanceValidator extends BaseValidator implements IResourceValidator { - public class StructureDefinitionSorterByUrl implements Comparator { - - @Override - public int compare(StructureDefinition o1, StructureDefinition o2) { - return o1.getUrl().compareTo(o2.getUrl()); - } - - } - - public class CanonicalTypeSorter implements Comparator { - - @Override - public int compare(CanonicalType o1, CanonicalType o2) { - return o1.getValue().compareTo(o2.getValue()); - } - - } - - public class CanonicalResourceLookupResult { - - private CanonicalResource resource; - private String error; - - public CanonicalResourceLookupResult(CanonicalResource resource) { - this.resource = resource; - } - - public CanonicalResourceLookupResult(String error) { - this.error = error; - } - } - private static final String EXECUTED_CONSTRAINT_LIST = "validator.executed.invariant.list"; private static final String EXECUTION_ID = "validator.execution.id"; private static final String HTML_FRAGMENT_REGEX = "[a-zA-Z]\\w*(((\\s+)(\\S)*)*)"; @@ -302,7 +273,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat @Override public List resolveConstant(Object appContext, String name, boolean beforeContext) throws PathEngineException { - ValidatorHostContext c = (ValidatorHostContext) appContext; + ValidationContext c = (ValidationContext) appContext; if (externalHostServices != null) return externalHostServices.resolveConstant(c.getAppContext(), name, beforeContext); else @@ -320,7 +291,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return null; } } - ValidatorHostContext c = (ValidatorHostContext) appContext; + ValidationContext c = (ValidationContext) appContext; if (externalHostServices != null) return externalHostServices.resolveConstantType(c.getAppContext(), name); else @@ -352,7 +323,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat @Override public Base resolveReference(Object appContext, String url, Base refContext) throws FHIRException { - ValidatorHostContext c = (ValidatorHostContext) appContext; + ValidationContext c = (ValidationContext) appContext; if (refContext != null && refContext.hasUserData("validator.bundle.resolution")) { return (Base) refContext.getUserData("validator.bundle.resolution"); @@ -397,7 +368,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat @Override public boolean conformsToProfile(Object appContext, Base item, String url) throws FHIRException { - ValidatorHostContext ctxt = (ValidatorHostContext) appContext; + ValidationContext ctxt = (ValidationContext) appContext; StructureDefinition sd = context.fetchResource(StructureDefinition.class, url); if (sd == null) { throw new FHIRException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_, url)); @@ -409,7 +380,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat try { Element e = new ObjectConverter(context).convert((Resource) item); setParents(e); - self.validateResource(new ValidatorHostContext(ctxt.getAppContext(), e), valerrors, e, e, sd, IdStatus.OPTIONAL, new NodeStack(context, null, e, validationLanguage), null, + self.validateResource(new ValidationContext(ctxt.getAppContext(), e), valerrors, e, e, sd, IdStatus.OPTIONAL, new NodeStack(context, null, e, validationLanguage), null, mode); } catch (IOException e1) { throw new FHIRException(e1); @@ -417,11 +388,11 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } else if (item instanceof Element) { Element e = (Element) item; if (e.getSpecial() == SpecialElement.CONTAINED) { - self.validateResource(new ValidatorHostContext(ctxt.getAppContext(), e, ctxt.getRootResource(), ctxt.getGroupingResource()), valerrors, e, e, sd, IdStatus.OPTIONAL, new NodeStack(context, null, e, validationLanguage), null, mode); + self.validateResource(new ValidationContext(ctxt.getAppContext(), e, ctxt.getRootResource(), ctxt.getGroupingResource()), valerrors, e, e, sd, IdStatus.OPTIONAL, new NodeStack(context, null, e, validationLanguage), null, mode); } else if (e.getSpecial() != null) { - self.validateResource(new ValidatorHostContext(ctxt.getAppContext(), e, e, ctxt.getRootResource()), valerrors, e, e, sd, IdStatus.OPTIONAL, new NodeStack(context, null, e, validationLanguage), null, mode); + self.validateResource(new ValidationContext(ctxt.getAppContext(), e, e, ctxt.getRootResource()), valerrors, e, e, sd, IdStatus.OPTIONAL, new NodeStack(context, null, e, validationLanguage), null, mode); } else { - self.validateResource(new ValidatorHostContext(ctxt.getAppContext(), e), valerrors, e, e, sd, IdStatus.OPTIONAL, new NodeStack(context, null, e, validationLanguage), null, mode); + self.validateResource(new ValidationContext(ctxt.getAppContext(), e), valerrors, e, e, sd, IdStatus.OPTIONAL, new NodeStack(context, null, e, validationLanguage), null, mode); } } else throw new NotImplementedException(context.formatMessage(I18nConstants.NOT_DONE_YET_VALIDATORHOSTSERVICESCONFORMSTOPROFILE_WHEN_ITEM_IS_NOT_AN_ELEMENT)); @@ -441,7 +412,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat @Override public ValueSet resolveValueSet(Object appContext, String url) { - ValidatorHostContext c = (ValidatorHostContext) appContext; + ValidationContext c = (ValidationContext) appContext; if (c.getProfile() != null && url.startsWith("#")) { for (Resource r : c.getProfile().getContained()) { if (r.getId().equals(url.substring(1))) { @@ -929,7 +900,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat long t = System.nanoTime(); NodeStack stack = new NodeStack(context, path, element, validationLanguage); if (profiles == null || profiles.isEmpty()) { - validateResource(new ValidatorHostContext(appContext, element), errors, element, element, null, resourceIdRule, stack.resetIds(), null, new ValidationMode(ValidationReason.Validation, ProfileSource.BaseDefinition)); + validateResource(new ValidationContext(appContext, element), errors, element, element, null, resourceIdRule, stack.resetIds(), null, new ValidationMode(ValidationReason.Validation, ProfileSource.BaseDefinition)); } else { int i = 0; while (i < profiles.size()) { @@ -947,7 +918,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat i++; } for (StructureDefinition defn : profiles) { - validateResource(new ValidatorHostContext(appContext, element), errors, element, element, defn, resourceIdRule, stack.resetIds(), null, new ValidationMode(ValidationReason.Validation, ProfileSource.ConfigProfile)); + validateResource(new ValidationContext(appContext, element), errors, element, element, defn, resourceIdRule, stack.resetIds(), null, new ValidationMode(ValidationReason.Validation, ProfileSource.ConfigProfile)); } } if (hintAboutNonMustSupport) { @@ -1992,7 +1963,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return ok; } - private boolean checkExtension(ValidatorHostContext hostContext, List errors, String path, Element resource, Element container, Element element, ElementDefinition def, StructureDefinition profile, NodeStack stack, NodeStack containerStack, String extensionUrl, PercentageTracker pct, ValidationMode mode) throws FHIRException { + private boolean checkExtension(ValidationContext valContext, List errors, String path, Element resource, Element container, Element element, ElementDefinition def, StructureDefinition profile, NodeStack stack, NodeStack containerStack, String extensionUrl, PercentageTracker pct, ValidationMode mode) throws FHIRException { boolean ok = true; String url = element.getNamedChildValue("url"); String u = url.contains("|") ? url.substring(0, url.indexOf("|")) : url; @@ -2040,7 +2011,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } } if (ex != null) { - trackUsage(ex, hostContext, element); + trackUsage(ex, valContext, element); // check internal definitions are coherent if (isModifier) { ok = rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), path + "[url='" + url + "']", def.getIsModifier() == isModifier, I18nConstants.EXTENSION_EXT_MODIFIER_MISMATCHY) && ok; @@ -2049,7 +2020,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } // 1. can this extension be used here? - ok = checkExtensionContext(hostContext.getAppContext(), errors, resource, container, ex, containerStack, hostContext, isModifier) && ok; + ok = checkExtensionContext(valContext.getAppContext(), errors, resource, container, ex, containerStack, valContext, isModifier) && ok; ok = checkDefinitionStatus(errors, element, path, ex, profile, context.formatMessage(I18nConstants.MSG_DEPENDS_ON_EXTENSION)) && ok; if (isModifier) @@ -2068,7 +2039,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat ok = rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), path, allowedTypes.isEmpty(), I18nConstants.EXTENSION_EXT_SIMPLE_ABSENT, url) && ok; // 3. is the content of the extension valid? - ok = validateElement(hostContext, errors, ex, ex.getSnapshot().getElement().get(0), null, null, resource, element, "Extension", stack, false, true, url, pct, mode) && ok; + ok = validateElement(valContext, errors, ex, ex.getSnapshot().getElement().get(0), null, null, resource, element, "Extension", stack, false, true, url, pct, mode) && ok; } return ok; @@ -2119,7 +2090,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return res; } - private boolean checkExtensionContext(Object appContext, List errors, Element resource, Element container, StructureDefinition definition, NodeStack stack, ValidatorHostContext hostContext, boolean modifier) { + private boolean checkExtensionContext(Object appContext, List errors, Element resource, Element container, StructureDefinition definition, NodeStack stack, ValidationContext valContext, boolean modifier) { String extUrl = definition.getUrl(); boolean ok = false; CommaSeparatedStringBuilder contexts = new CommaSeparatedStringBuilder(); @@ -2209,7 +2180,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } else if (ctxt.getType() == ExtensionContextType.FHIRPATH) { contexts.append("p:" + ctxt.getExpression()); // The context is all elements that match the FHIRPath query found in the expression. - List res = fpe.evaluate(hostContext, resource, hostContext.getRootResource(), resource, fpe.parse(ctxt.getExpression())); + List res = fpe.evaluate(valContext, resource, valContext.getRootResource(), resource, fpe.parse(ctxt.getExpression())); if (res.contains(container)) { ok = true; } @@ -2229,7 +2200,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } else { if (definition.hasContextInvariant()) { for (StringType s : definition.getContextInvariant()) { - if (!fpe.evaluateToBoolean(hostContext, resource, hostContext.getRootResource(), container, fpe.parse(s.getValue()))) { + if (!fpe.evaluateToBoolean(valContext, resource, valContext.getRootResource(), container, fpe.parse(s.getValue()))) { if (definition.hasUserData(XVerExtensionManager.XVER_EXT_MARKER)) { warning(errors, NO_RULE_DATE, IssueType.STRUCTURE, container.line(), container.col(), stack.getLiteralPath(), false, I18nConstants.PROFILE_EXT_NOT_HERE, extUrl, s.getValue()); return true; @@ -2291,7 +2262,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } else if (sd.getType().equals(resource.fhirType())) { List valerrors = new ArrayList(); ValidationMode mode = new ValidationMode(ValidationReason.Expression, ProfileSource.FromExpression); - validateResource(new ValidatorHostContext(appContext, resource), valerrors, resource, resource, sd, IdStatus.OPTIONAL, new NodeStack(context, null, resource, validationLanguage), null, mode); + validateResource(new ValidationContext(appContext, resource), valerrors, resource, resource, sd, IdStatus.OPTIONAL, new NodeStack(context, null, resource, validationLanguage), null, mode); boolean ok = true; List record = new ArrayList<>(); for (ValidationMessage v : valerrors) { @@ -2517,7 +2488,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return ok; } - private boolean checkPrimitive(ValidatorHostContext hostContext, List errors, String path, String type, ElementDefinition context, Element e, StructureDefinition profile, NodeStack node) throws FHIRException { + private boolean checkPrimitive(ValidationContext valContext, List errors, String path, String type, ElementDefinition context, Element e, StructureDefinition profile, NodeStack node) throws FHIRException { boolean ok = true; if (isBlank(e.primitiveValue())) { if (e.primitiveValue() == null) @@ -2626,7 +2597,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, Utilities.isAbsoluteUrl(url), node.isContained() ? I18nConstants.TYPE_SPECIFIC_CHECKS_CANONICAL_CONTAINED : I18nConstants.TYPE_SPECIFIC_CHECKS_CANONICAL_ABSOLUTE, url) && ok; } else if (!e.getProperty().getDefinition().getPath().equals("Bundle.entry.fullUrl")) { // we don't check fullUrl here; it's not a reference, it's a definition. It'll get checked as part of checking the bundle - ok = validateReference(hostContext, errors, path, type, context, e, url) && ok; + ok = validateReference(valContext, errors, path, type, context, e, url) && ok; } } if (type.equals(ID) && !"Resource.id".equals(context.getBase().getPath())) { @@ -2799,7 +2770,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if ("StructureDefinition.type".equals(context.getPath()) && "http://hl7.org/fhir/StructureDefinition/StructureDefinition".equals(profile.getUrl())) { ok = checkTypeValue(errors, path, e, node.getElement()); } else { - ok = checkPrimitiveBinding(hostContext, errors, path, type, context, e, profile, node) && ok; + ok = checkPrimitiveBinding(valContext, errors, path, type, context, e, profile, node) && ok; } } @@ -2924,7 +2895,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return Utilities.escapeJson(s); } - public boolean validateReference(ValidatorHostContext hostContext, List errors, String path, String type, ElementDefinition context, Element e, String url) { + public boolean validateReference(ValidationContext valContext, List errors, String path, String type, ElementDefinition context, Element e, String url) { boolean ok = true; // now, do we check the URI target? if (fetcher != null && !type.equals("uuid")) { @@ -2933,14 +2904,14 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat found = isDefinitionURL(url) || (allowExamples && (url.contains("example.org") || url.contains("acme.com")) || url.contains("acme.org")) /* || (url.startsWith("http://hl7.org/fhir/tools")) */ || SpecialExtensions.isKnownExtension(url) || isXverUrl(url); if (!found) { - found = fetcher.resolveURL(this, hostContext, path, url, type, type.equals("canonical")); + found = fetcher.resolveURL(this, valContext, path, url, type, type.equals("canonical")); } } catch (IOException e1) { found = false; } if (!found) { if (type.equals("canonical")) { - ReferenceValidationPolicy rp = policyAdvisor == null ? ReferenceValidationPolicy.CHECK_VALID : policyAdvisor.policyForReference(this, hostContext, path, url); + ReferenceValidationPolicy rp = policyAdvisor == null ? ReferenceValidationPolicy.CHECK_VALID : policyAdvisor.policyForReference(this, valContext, path, url); if (rp == ReferenceValidationPolicy.CHECK_EXISTS || rp == ReferenceValidationPolicy.CHECK_EXISTS_AND_TYPE) { ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_CANONICAL_RESOLVE, url) && ok; } else { @@ -2957,12 +2928,12 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } } else { if (type.equals("canonical")) { - ReferenceValidationPolicy rp = policyAdvisor == null ? ReferenceValidationPolicy.CHECK_VALID : policyAdvisor.policyForReference(this, hostContext, path, url); + ReferenceValidationPolicy rp = policyAdvisor == null ? ReferenceValidationPolicy.CHECK_VALID : policyAdvisor.policyForReference(this, valContext, path, url); if (rp == ReferenceValidationPolicy.CHECK_EXISTS_AND_TYPE || rp == ReferenceValidationPolicy.CHECK_TYPE_IF_EXISTS || rp == ReferenceValidationPolicy.CHECK_VALID) { try { Resource r = null; if (url.startsWith("#")) { - r = loadContainedResource(errors, path, hostContext.getRootResource(), url.substring(1), Resource.class); + r = loadContainedResource(errors, path, valContext.getRootResource(), url.substring(1), Resource.class); } if (r == null) { r = fetcher.fetchCanonicalResource(this, url); @@ -3243,7 +3214,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return ok; } - private boolean checkPrimitiveBinding(ValidatorHostContext hostContext, List errors, String path, String type, ElementDefinition elementContext, Element element, StructureDefinition profile, NodeStack stack) { + private boolean checkPrimitiveBinding(ValidationContext valContext, List errors, String path, String type, ElementDefinition elementContext, Element element, StructureDefinition profile, NodeStack stack) { // We ignore bindings that aren't on string, uri or code if (!element.hasPrimitiveValue() || !("code".equals(type) || "string".equals(type) || "uri".equals(type) || "url".equals(type) || "canonical".equals(type))) { return true; @@ -3268,7 +3239,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } } else { CodedContentValidationPolicy validationPolicy = getPolicyAdvisor() == null ? - CodedContentValidationPolicy.VALUESET : getPolicyAdvisor().policyForCodedContent(this, hostContext, stack.getLiteralPath(), elementContext, profile, BindingKind.PRIMARY, vs, new ArrayList<>()); + CodedContentValidationPolicy.VALUESET : getPolicyAdvisor().policyForCodedContent(this, valContext, stack.getLiteralPath(), elementContext, profile, BindingKind.PRIMARY, vs, new ArrayList<>()); if (validationPolicy != CodedContentValidationPolicy.IGNORE) { long t = System.nanoTime(); @@ -3563,7 +3534,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return ok; } - private boolean checkReference(ValidatorHostContext hostContext, + private boolean checkReference(ValidationContext valContext, List errors, String path, Element element, @@ -3590,7 +3561,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat warning(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), path, !isSuspiciousReference(ref), I18nConstants.REFERENCE_REF_SUSPICIOUS, ref); BooleanHolder bh = new BooleanHolder(); - ResolvedReference we = localResolve(ref, stack, errors, path, hostContext.getRootResource(), hostContext.getGroupingResource(), element, bh); + ResolvedReference we = localResolve(ref, stack, errors, path, valContext.getRootResource(), valContext.getGroupingResource(), element, bh); ok = bh.ok() && ok; String refType; if (ref.startsWith("#")) { @@ -3610,7 +3581,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (policyAdvisor == null) { pol = ReferenceValidationPolicy.IGNORE; } else { - pol = policyAdvisor.policyForReference(this, hostContext.getAppContext(), path, ref); + pol = policyAdvisor.policyForReference(this, valContext.getAppContext(), path, ref); } } @@ -3631,7 +3602,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat ext = fetchCache.get(ref); } else { try { - ext = fetcher.fetch(this, hostContext.getAppContext(), ref); + ext = fetcher.fetch(this, valContext.getAppContext(), ref); } catch (IOException e) { if (STACK_TRACE) e.printStackTrace(); throw new FHIRException(e); @@ -3718,12 +3689,12 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat int goodCount = 0; for (StructureDefinition pr : profiles) { List profileErrors = new ArrayList(); - validateResource(we.hostContext(hostContext, pr), profileErrors, we.getResource(), we.getFocus(), pr, + validateResource(we.valContext(valContext, pr), profileErrors, we.getResource(), we.getFocus(), pr, IdStatus.OPTIONAL, we.getStack().resetIds(), pct, vmode.withReason(ValidationReason.MatchingSlice)); if (!hasErrors(profileErrors)) { goodCount++; goodProfiles.put(pr, profileErrors); - trackUsage(pr, hostContext, element); + trackUsage(pr, valContext, element); } else { badProfiles.put(pr, profileErrors); } @@ -4642,7 +4613,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat * @throws IOException * @throws FHIRException */ - private boolean sliceMatches(ValidatorHostContext hostContext, Element element, String path, ElementDefinition slicer, ElementDefinition ed, StructureDefinition profile, List errors, List sliceInfo, NodeStack stack, StructureDefinition srcProfile) throws DefinitionException, FHIRException { + private boolean sliceMatches(ValidationContext valContext, Element element, String path, ElementDefinition slicer, ElementDefinition ed, StructureDefinition profile, List errors, List sliceInfo, NodeStack stack, StructureDefinition srcProfile) throws DefinitionException, FHIRException { if (!slicer.getSlicing().hasDiscriminator()) return false; // cannot validate in this case @@ -4746,7 +4717,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } else { } - ValidatorHostContext shc = hostContext.forSlicing(); + ValidationContext shc = valContext.forSlicing(); boolean pass = evaluateSlicingExpression(shc, element, path, profile, n); if (!pass) { slicingHint(sliceInfo, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), path, false, isProfile(slicer), (context.formatMessage(I18nConstants.DOES_NOT_MATCH_SLICE_, ed.getSliceName(), n.toString().substring(8).trim())), "discriminator = " + Utilities.escapeXml(n.toString()), null); @@ -4784,12 +4755,12 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return false; } - public boolean evaluateSlicingExpression(ValidatorHostContext hostContext, Element element, String path, StructureDefinition profile, ExpressionNode n) throws FHIRException { + public boolean evaluateSlicingExpression(ValidationContext valContext, Element element, String path, StructureDefinition profile, ExpressionNode n) throws FHIRException { String msg; boolean pass; try { long t = System.nanoTime(); - pass = fpe.evaluateToBoolean(hostContext.forProfile(profile), hostContext.getResource(), hostContext.getRootResource(), element, n); + pass = fpe.evaluateToBoolean(valContext.forProfile(profile), valContext.getResource(), valContext.getRootResource(), element, n); timeTracker.fpe(t); msg = fpe.forLog(); } catch (Exception ex) { @@ -5079,7 +5050,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } // checkSpecials = we're only going to run these tests if we are actually validating this content (as opposed to we looked it up) - private boolean start(ValidatorHostContext hostContext, List errors, Element resource, Element element, StructureDefinition defn, NodeStack stack, PercentageTracker pct, ValidationMode mode) throws FHIRException { + private boolean start(ValidationContext valContext, List errors, Element resource, Element element, StructureDefinition defn, NodeStack stack, PercentageTracker pct, ValidationMode mode) throws FHIRException { boolean ok = !hasErrors(errors); checkLang(resource, stack); @@ -5099,7 +5070,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } resolveBundleReferences(element, new ArrayList()); } - ok = startInner(hostContext, errors, resource, element, defn, stack, hostContext.isCheckSpecials(), pct, mode) && ok; + ok = startInner(valContext, errors, resource, element, defn, stack, valContext.isCheckSpecials(), pct, mode) && ok; if (pctOwned) { pct.done(); } @@ -5118,7 +5089,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (pctOwned) { pct = new PercentageTracker(resource.countDescendents(), resource.fhirType(), sdi.getUrl(), logProgress); } - ok = startInner(hostContext, errors, resource, element, sdi, stack, false, pct, mode.withSource(ProfileSource.ProfileDependency)) && ok; + ok = startInner(valContext, errors, resource, element, sdi, stack, false, pct, mode.withSource(ProfileSource.ProfileDependency)) && ok; if (pctOwned) { pct.done(); } @@ -5166,7 +5137,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (pctOwned) { pct = new PercentageTracker(resource.countDescendents(), resource.fhirType(), sd.getUrl(), logProgress); } - ok = startInner(hostContext, errors, resource, element, sd, stack, false, pct, mode.withSource(ProfileSource.MetaProfile)) && ok; + ok = startInner(valContext, errors, resource, element, sd, stack, false, pct, mode.withSource(ProfileSource.MetaProfile)) && ok; if (pctOwned) { pct.done(); } @@ -5183,7 +5154,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (pctOwned) { pct = new PercentageTracker(resource.countDescendents(), resource.fhirType(), sdi.getUrl(), logProgress); } - ok = startInner(hostContext, errors, resource, element, sdi, stack, false, pct, mode.withSource(ProfileSource.ProfileDependency)) && ok; + ok = startInner(valContext, errors, resource, element, sdi, stack, false, pct, mode.withSource(ProfileSource.ProfileDependency)) && ok; if (pctOwned) { pct.done(); } @@ -5210,7 +5181,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (pctOwned) { pct = new PercentageTracker(resource.countDescendents(), resource.fhirType(), sd.getVersionedUrl(), logProgress); } - ok = startInner(hostContext, errors, resource, element, sd, stack, false, pct, mode.withSource(ProfileSource.GlobalProfile)) && ok; + ok = startInner(valContext, errors, resource, element, sd, stack, false, pct, mode.withSource(ProfileSource.GlobalProfile)) && ok; if (pctOwned) { pct.done(); } @@ -5227,10 +5198,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat String url = profile.primitiveValue(); CanonicalResourceLookupResult cr = crLookups.get(url); if (cr != null) { - if (cr.error != null) { - warning(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), stack.getLiteralPath() + ".meta.profile[" + i + "]", false, I18nConstants.VALIDATION_VAL_PROFILE_UNKNOWN_ERROR, url, cr.error); + if (cr.getError() != null) { + warning(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), stack.getLiteralPath() + ".meta.profile[" + i + "]", false, I18nConstants.VALIDATION_VAL_PROFILE_UNKNOWN_ERROR, url, cr.getError()); } else { - sd = (StructureDefinition) cr.resource; + sd = (StructureDefinition) cr.getResource(); } } else { try { @@ -5311,7 +5282,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } } - public boolean startInner(ValidatorHostContext hostContext, List errors, Element resource, Element element, StructureDefinition defn, NodeStack stack, boolean checkSpecials, PercentageTracker pct, ValidationMode mode) { + public boolean startInner(ValidationContext valContext, List errors, Element resource, Element element, StructureDefinition defn, NodeStack stack, boolean checkSpecials, PercentageTracker pct, ValidationMode mode) { // the first piece of business is to see if we've validated this resource against this profile before. // if we have (*or if we still are*), then we'll just return our existing errors boolean ok = true; @@ -5329,8 +5300,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), stack.getLiteralPath(), defn.hasSnapshot(), I18nConstants.VALIDATION_VAL_PROFILE_NOSNAPSHOT, defn.getVersionedUrl())) { List localErrors = new ArrayList(); resTracker.startValidating(defn); - trackUsage(defn, hostContext, element); - ok = validateElement(hostContext, localErrors, defn, defn.getSnapshot().getElement().get(0), null, null, resource, element, element.getName(), stack, false, true, null, pct, mode) && ok; + trackUsage(defn, valContext, element); + ok = validateElement(valContext, localErrors, defn, defn.getSnapshot().getElement().get(0), null, null, resource, element, element.getName(), stack, false, true, null, pct, mode) && ok; resTracker.storeOutcomes(defn, localErrors); for (ValidationMessage vm : localErrors) { if (!errors.contains(vm)) { @@ -5341,13 +5312,13 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat ok = false; } if (checkSpecials) { - ok = checkSpecials(hostContext, errors, element, stack, checkSpecials, pct, mode) && ok; + ok = checkSpecials(valContext, errors, element, stack, checkSpecials, pct, mode) && ok; ok = validateResourceRules(errors, element, stack) && ok; } return ok; } - public boolean checkSpecials(ValidatorHostContext hostContext, List errors, Element element, NodeStack stack, boolean checkSpecials, PercentageTracker pct, ValidationMode mode) { + public boolean checkSpecials(ValidationContext valContext, List errors, Element element, NodeStack stack, boolean checkSpecials, PercentageTracker pct, ValidationMode mode) { boolean ok = true; long t = System.nanoTime(); @@ -5367,17 +5338,17 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } } if (element.getType().equals(BUNDLE)) { - return new BundleValidator(this, serverBase).validateBundle(errors, element, stack, checkSpecials, hostContext, pct, mode) && ok; + return new BundleValidator(this, serverBase).validateBundle(errors, element, stack, checkSpecials, valContext, pct, mode) && ok; } else if (element.getType().equals("Observation")) { return validateObservation(errors, element, stack) && ok; } else if (element.getType().equals("Questionnaire")) { return new QuestionnaireValidator(this, myEnableWhenEvaluator, fpe, questionnaireMode).validateQuestionannaire(errors, element, element, stack) && ok; } else if (element.getType().equals("QuestionnaireResponse")) { - return new QuestionnaireValidator(this, myEnableWhenEvaluator, fpe, questionnaireMode).validateQuestionannaireResponse(hostContext, errors, element, stack) && ok; + return new QuestionnaireValidator(this, myEnableWhenEvaluator, fpe, questionnaireMode).validateQuestionannaireResponse(valContext, errors, element, stack) && ok; } else if (element.getType().equals("Measure")) { - return new MeasureValidator(this).validateMeasure(hostContext, errors, element, stack) && ok; + return new MeasureValidator(this).validateMeasure(valContext, errors, element, stack) && ok; } else if (element.getType().equals("MeasureReport")) { - return new MeasureValidator(this).validateMeasureReport(hostContext, errors, element, stack) && ok; + return new MeasureValidator(this).validateMeasureReport(valContext, errors, element, stack) && ok; } else if (element.getType().equals("CapabilityStatement")) { return validateCapabilityStatement(errors, element, stack) && ok; } else if (element.getType().equals("CodeSystem")) { @@ -5538,7 +5509,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return ok; } - private boolean validateContains(ValidatorHostContext hostContext, List errors, String path, + private boolean validateContains(ValidationContext valContext, List errors, String path, ElementDefinition child, ElementDefinition context, Element resource, Element element, NodeStack stack, IdStatus idstatus, StructureDefinition parentProfile, PercentageTracker pct, ValidationMode mode) throws FHIRException { boolean ok = true; @@ -5556,7 +5527,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat ContainedReferenceValidationPolicy containedValidationPolicy = getPolicyAdvisor() == null ? ContainedReferenceValidationPolicy.CHECK_VALID : getPolicyAdvisor().policyForContained(this, - hostContext, context.fhirType(), context.getId(), special, path, parentProfile.getUrl()); + valContext, context.fhirType(), context.getId(), special, path, parentProfile.getUrl()); if (containedValidationPolicy.ignore()) { return ok; @@ -5583,13 +5554,13 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } else if (isValidResourceType(resourceName, typeForResource)) { if (containedValidationPolicy.checkValid()) { // special case: resource wrapper is reset if we're crossing a bundle boundary, but not otherwise - ValidatorHostContext hc = null; + ValidationContext hc = null; if (special == SpecialElement.BUNDLE_ENTRY || special == SpecialElement.BUNDLE_OUTCOME || special == SpecialElement.BUNDLE_ISSUES || special == SpecialElement.PARAMETER) { resource = element; - assert Utilities.existsInList(hostContext.getResource().fhirType(), "Bundle", "Parameters") : "Containing Resource is "+hostContext.getResource().fhirType()+", expected Bundle or Parameters at "+stack.getLiteralPath(); - hc = hostContext.forEntry(element, hostContext.getResource()); // root becomes the grouping resource (should be either bundle or parameters) + assert Utilities.existsInList(valContext.getResource().fhirType(), "Bundle", "Parameters") : "Containing Resource is "+valContext.getResource().fhirType()+", expected Bundle or Parameters at "+stack.getLiteralPath(); + hc = valContext.forEntry(element, valContext.getResource()); // root becomes the grouping resource (should be either bundle or parameters) } else { - hc = hostContext.forContained(element); + hc = valContext.forContained(element); } stack.resetIds(); @@ -5609,13 +5580,13 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } } - checkSpecials(hostContext, errors, element, stack, ok, pct, mode); + checkSpecials(valContext, errors, element, stack, ok, pct, mode); if (typeForResource.getProfile().size() == 1) { long t = System.nanoTime(); StructureDefinition profile = this.context.fetchResource(StructureDefinition.class, typeForResource.getProfile().get(0).asStringValue(), parentProfile); timeTracker.sd(t); - trackUsage(profile, hostContext, element); + trackUsage(profile, valContext, element); if (rule(errors, NO_RULE_DATE, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), profile != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOPROFILE_EXPL, special.toHuman(), resourceName, typeForResource.getProfile().get(0).asStringValue())) { ok = validateResource(hc, errors, resource, element, profile, idstatus, stack, pct, mode) && ok; @@ -5627,7 +5598,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat StructureDefinition profile = this.context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + resourceName); timeTracker.sd(t); - trackUsage(profile, hostContext, element); + trackUsage(profile, valContext, element); if (rule(errors, NO_RULE_DATE, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), profile != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOPROFILE_TYPE, special == null ? "??" : special.toHuman(), resourceName)) { ok = validateResource(hc, errors, resource, element, profile, idstatus, stack, pct, mode) && ok; @@ -5648,7 +5619,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat timeTracker.sd(t); if (rule(errors, NO_RULE_DATE, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), profile != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOPROFILE_TYPE, special == null ? "??" : special.toHuman(), u.asStringValue())) { - trackUsage(profile, hostContext, element); + trackUsage(profile, valContext, element); List perrors = new ArrayList<>(); errorsList.add(perrors); if (validateResource(hc, perrors, resource, element, profile, idstatus, stack, pct, mode)) { @@ -5735,7 +5706,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } - private boolean validateElement(ValidatorHostContext hostContext, List errors, StructureDefinition profile, ElementDefinition definition, StructureDefinition cprofile, ElementDefinition context, + private boolean validateElement(ValidationContext valContext, List errors, StructureDefinition profile, ElementDefinition definition, StructureDefinition cprofile, ElementDefinition context, Element resource, Element element, String actualType, NodeStack stack, boolean inCodeableConcept, boolean checkDisplayInContext, String extensionUrl, PercentageTracker pct, ValidationMode mode) throws FHIRException { boolean ok = true; @@ -5757,7 +5728,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat ValidationInfo vi = element.addDefinition(profile, definition, mode); // check type invariants - ok = checkInvariants(hostContext, errors, profile, definition, resource, element, stack, false) & ok; + ok = checkInvariants(valContext, errors, profile, definition, resource, element, stack, false) & ok; if (definition.getFixed() != null) { ok = checkFixedValue(errors, stack.getLiteralPath(), element, definition.getFixed(), profile.getVersionedUrl(), definition.getSliceName(), null, false) && ok; } @@ -5772,21 +5743,21 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat vi.setValid(false); return false; // there'll be an error elsewhere in this case, and we're going to stop. } - childDefinitions = getActualTypeChildren(hostContext, element, actualType); + childDefinitions = getActualTypeChildren(valContext, element, actualType); } else if (definition.getType().size() > 1) { // this only happens when the profile constrains the abstract children but leaves th choice open. if (actualType == null) { vi.setValid(false); return false; // there'll be an error elsewhere in this case, and we're going to stop. } - SourcedChildDefinitions typeChildDefinitions = getActualTypeChildren(hostContext, element, actualType); + SourcedChildDefinitions typeChildDefinitions = getActualTypeChildren(valContext, element, actualType); // what were going to do is merge them - the type is not allowed to constrain things that the child definitions already do (well, if it does, it'll be ignored) childDefinitions = mergeChildLists(childDefinitions, typeChildDefinitions, definition.getPath(), actualType); } List children = listChildren(element, stack); BooleanHolder bh = new BooleanHolder(); - List problematicPaths = assignChildren(hostContext, errors, profile, resource, stack, childDefinitions, children, bh); + List problematicPaths = assignChildren(valContext, errors, profile, resource, stack, childDefinitions, children, bh); ok = bh.ok() && ok; ok = checkCardinalities(errors, profile, element, stack, childDefinitions, children, problematicPaths) && ok; @@ -5794,7 +5765,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat // 5. inspect each child for validity for (ElementInfo ei : children) { - ok = checkChild(hostContext, errors, profile, definition, resource, element, actualType, stack, inCodeableConcept, checkDisplayInContext, ei, extensionUrl, pct, mode) && ok; + ok = checkChild(valContext, errors, profile, definition, resource, element, actualType, stack, inCodeableConcept, checkDisplayInContext, ei, extensionUrl, pct, mode) && ok; } vi.setValid(ok); return ok; @@ -5819,7 +5790,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } // todo: the element definition in context might assign a constrained profile for the type? - public SourcedChildDefinitions getActualTypeChildren(ValidatorHostContext hostContext, Element element, String actualType) { + public SourcedChildDefinitions getActualTypeChildren(ValidationContext valContext, Element element, String actualType) { SourcedChildDefinitions childDefinitions; StructureDefinition dt = null; if (isAbsolute(actualType)) @@ -5828,13 +5799,13 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat dt = this.context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + actualType); if (dt == null) throw new DefinitionException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_ACTUAL_TYPE_, actualType)); - trackUsage(dt, hostContext, element); + trackUsage(dt, valContext, element); childDefinitions = profileUtilities.getChildMap(dt, dt.getSnapshot().getElement().get(0)); return childDefinitions; } - public boolean checkChild(ValidatorHostContext hostContext, List errors, StructureDefinition profile, ElementDefinition definition, + public boolean checkChild(ValidationContext valContext, List errors, StructureDefinition profile, ElementDefinition definition, Element resource, Element element, String actualType, NodeStack stack, boolean inCodeableConcept, boolean checkDisplayInContext, ElementInfo ei, String extensionUrl, PercentageTracker pct, ValidationMode mode) throws FHIRException, DefinitionException { boolean ok = true; @@ -5846,13 +5817,13 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (debug) { System.out.println(Utilities.padLeft("", ' ', stack.depth())+ "Check "+ei.getPath()+" against defn "+ei.definition.getId()+" from "+profile.getVersionedUrl()+time()); } - ok = checkChildByDefinition(hostContext, errors, profile, definition, resource, element, actualType, stack, inCodeableConcept, checkDisplayInContext, ei, extensionUrl, ei.definition, false, pct, mode) && ok; + ok = checkChildByDefinition(valContext, errors, profile, definition, resource, element, actualType, stack, inCodeableConcept, checkDisplayInContext, ei, extensionUrl, ei.definition, false, pct, mode) && ok; } if (ei.slice != null) { if (debug) { System.out.println(Utilities.padLeft("", ' ', stack.depth())+ "Check "+ei.getPath()+" against slice "+ei.slice.getId()+time()); } - ok = checkChildByDefinition(hostContext, errors, profile, definition, resource, element, actualType, stack, inCodeableConcept, checkDisplayInContext, ei, extensionUrl, ei.slice, true, pct, mode) && ok; + ok = checkChildByDefinition(valContext, errors, profile, definition, resource, element, actualType, stack, inCodeableConcept, checkDisplayInContext, ei, extensionUrl, ei.slice, true, pct, mode) && ok; } return ok; } @@ -5864,7 +5835,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return s; } - public boolean checkChildByDefinition(ValidatorHostContext hostContext, List errors, StructureDefinition profile, + public boolean checkChildByDefinition(ValidationContext valContext, List errors, StructureDefinition profile, ElementDefinition definition, Element resource, Element element, String actualType, NodeStack stack, boolean inCodeableConcept, boolean checkDisplayInContext, ElementInfo ei, String extensionUrl, ElementDefinition checkDefn, boolean isSlice, PercentageTracker pct, ValidationMode mode) { boolean ok = true; @@ -5980,16 +5951,16 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat SpecialElement special = ei.getElement().getSpecial(); // this used to say // if (special == SpecialElement.BUNDLE_ENTRY || special == SpecialElement.BUNDLE_OUTCOME || special == SpecialElement.BUNDLE_ISSUES || special == SpecialElement.PARAMETER) { - // ok = checkInvariants(hostContext, errors, profile, typeDefn != null ? typeDefn : checkDefn, ei.getElement(), ei.getElement(), localStack, false) && ok; + // ok = checkInvariants(valContext, errors, profile, typeDefn != null ? typeDefn : checkDefn, ei.getElement(), ei.getElement(), localStack, false) && ok; // but this isn't correct - when the invariant is on the element, the invariant is in the context of the resource that contains the element. // changed 18-Jul 2023 - see https://chat.fhir.org/#narrow/stream/179266-fhirpath/topic/FHIRPath.20.25resource.20variable - ok = checkInvariants(hostContext, errors, profile, typeDefn != null ? typeDefn : checkDefn, resource, ei.getElement(), localStack, false) && ok; + ok = checkInvariants(valContext, errors, profile, typeDefn != null ? typeDefn : checkDefn, resource, ei.getElement(), localStack, false) && ok; ei.getElement().markValidation(profile, checkDefn); boolean elementValidated = false; if (type != null) { if (isPrimitiveType(type)) { - ok = checkPrimitive(hostContext, errors, ei.getPath(), type, checkDefn, ei.getElement(), profile, stack) && ok; + ok = checkPrimitive(valContext, errors, ei.getPath(), type, checkDefn, ei.getElement(), profile, stack) && ok; } else { if (checkDefn.hasFixed()) { ok = checkFixedValue(errors, ei.getPath(), ei.getElement(), checkDefn.getFixed(), profile.getVersionedUrl(), checkDefn.getSliceName(), null, false) && ok; @@ -6012,7 +5983,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat ok = bh.ok() & ok; thisIsCodeableConcept = true; } else if (type.equals("Reference")) { - ok = checkReference(hostContext, errors, ei.getPath(), ei.getElement(), profile, checkDefn, actualType, localStack, pct, mode) && ok; + ok = checkReference(valContext, errors, ei.getPath(), ei.getElement(), profile, checkDefn, actualType, localStack, pct, mode) && ok; // We only check extensions if we're not in a complex extension or if the element we're dealing with is not defined as part of that complex extension } else if (type.equals("Extension")) { Element eurl = ei.getElement().getNamedChild("url"); @@ -6021,7 +5992,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat thisExtension = url; if (rule(errors, NO_RULE_DATE, IssueType.INVALID, ei.getPath(), !Utilities.noString(url), I18nConstants.EXTENSION_EXT_URL_NOTFOUND)) { if (rule(errors, NO_RULE_DATE, IssueType.INVALID, ei.getPath(), (extensionUrl != null) || Utilities.isAbsoluteUrl(url), I18nConstants.EXTENSION_EXT_URL_ABSOLUTE)) { - ok = checkExtension(hostContext, errors, ei.getPath(), resource, element, ei.getElement(), checkDefn, profile, localStack, stack, extensionUrl, pct, mode) && ok; + ok = checkExtension(valContext, errors, ei.getPath(), resource, element, ei.getElement(), checkDefn, profile, localStack, stack, extensionUrl, pct, mode) && ok; } else { ok = false; } @@ -6032,7 +6003,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat ok = false; } } else if (type.equals("Resource") || isResource(type)) { - ok = validateContains(hostContext, errors, ei.getPath(), checkDefn, definition, resource, ei.getElement(), + ok = validateContains(valContext, errors, ei.getPath(), checkDefn, definition, resource, ei.getElement(), localStack, idStatusForEntry(element, ei), profile, pct, mode) && ok; // if elementValidated = true; // (str.matches(".*([.,/])work\\1$")) @@ -6050,7 +6021,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } } else { if (rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, ei.line(), ei.col(), stack.getLiteralPath(), checkDefn != null, I18nConstants.VALIDATION_VAL_CONTENT_UNKNOWN, ei.getName())) { - ok = validateElement(hostContext, errors, profile, checkDefn, null, null, resource, ei.getElement(), type, localStack, false, true, null, pct, mode) && ok; + ok = validateElement(valContext, errors, profile, checkDefn, null, null, resource, ei.getElement(), type, localStack, false, true, null, pct, mode) && ok; } else { ok = false; } @@ -6065,7 +6036,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat // the invariants (constraints) on the current element, because otherwise it only gets // checked against the primary type's invariants: LLoyd //if (p.getKind() == StructureDefinitionKind.PRIMITIVETYPE) { - // checkInvariants(hostContext, errors, ei.path, profile, ei.definition, null, null, resource, ei.element); + // checkInvariants(valContext, errors, ei.path, profile, ei.definition, null, null, resource, ei.element); //} ok = rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, ei.line(), ei.col(), ei.getPath(), p != null, I18nConstants.VALIDATION_VAL_NOTYPE, type) && ok; @@ -6092,7 +6063,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat p = this.context.fetchResource(StructureDefinition.class, typeProfile); if (rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, ei.line(), ei.col(), ei.getPath(), p != null, I18nConstants.VALIDATION_VAL_UNKNOWN_PROFILE, typeProfile)) { List profileErrors = new ArrayList(); - validateElement(hostContext, profileErrors, p, getElementByTail(p, tail), profile, checkDefn, resource, ei.getElement(), type, localStack, thisIsCodeableConcept, checkDisplay, thisExtension, pct, mode); // we don't track ok here + validateElement(valContext, profileErrors, p, getElementByTail(p, tail), profile, checkDefn, resource, ei.getElement(), type, localStack, thisIsCodeableConcept, checkDisplay, thisExtension, pct, mode); // we don't track ok here if (hasErrors(profileErrors)) badProfiles.put(typeProfile, profileErrors); else @@ -6124,24 +6095,24 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } } if (p != null) { - trackUsage(p, hostContext, element); + trackUsage(p, valContext, element); if (!elementValidated) { if (ei.getElement().getSpecial() == SpecialElement.BUNDLE_ENTRY || ei.getElement().getSpecial() == SpecialElement.BUNDLE_OUTCOME || ei.getElement().getSpecial() == SpecialElement.PARAMETER) - ok = validateElement(hostContext, errors, p, getElementByTail(p, tail), profile, checkDefn, ei.getElement(), ei.getElement(), type, localStack.resetIds(), thisIsCodeableConcept, checkDisplay, thisExtension, pct, mode) && ok; + ok = validateElement(valContext, errors, p, getElementByTail(p, tail), profile, checkDefn, ei.getElement(), ei.getElement(), type, localStack.resetIds(), thisIsCodeableConcept, checkDisplay, thisExtension, pct, mode) && ok; else - ok = validateElement(hostContext, errors, p, getElementByTail(p, tail), profile, checkDefn, resource, ei.getElement(), type, localStack, thisIsCodeableConcept, checkDisplay, thisExtension, pct, mode) && ok; + ok = validateElement(valContext, errors, p, getElementByTail(p, tail), profile, checkDefn, resource, ei.getElement(), type, localStack, thisIsCodeableConcept, checkDisplay, thisExtension, pct, mode) && ok; } int index = profile.getSnapshot().getElement().indexOf(checkDefn); if (index < profile.getSnapshot().getElement().size() - 1) { String nextPath = profile.getSnapshot().getElement().get(index + 1).getPath(); if (!nextPath.equals(checkDefn.getPath()) && nextPath.startsWith(checkDefn.getPath())) { if (ei.getElement().getSpecial() == SpecialElement.BUNDLE_ENTRY || ei.getElement().getSpecial() == SpecialElement.BUNDLE_OUTCOME || ei.getElement().getSpecial() == SpecialElement.PARAMETER) { - ok = validateElement(hostContext.forEntry(ei.getElement(), null), errors, profile, checkDefn, null, null, ei.getElement(), ei.getElement(), type, localStack, thisIsCodeableConcept, checkDisplay, thisExtension, pct, mode) && ok; + ok = validateElement(valContext.forEntry(ei.getElement(), null), errors, profile, checkDefn, null, null, ei.getElement(), ei.getElement(), type, localStack, thisIsCodeableConcept, checkDisplay, thisExtension, pct, mode) && ok; } else if (ei.getElement().getSpecial() == SpecialElement.CONTAINED) { - ok = validateElement(hostContext.forContained(ei.getElement()), errors, profile, checkDefn, null, null, ei.getElement(), ei.getElement(), type, localStack, thisIsCodeableConcept, checkDisplay, thisExtension, pct, mode) && ok; + ok = validateElement(valContext.forContained(ei.getElement()), errors, profile, checkDefn, null, null, ei.getElement(), ei.getElement(), type, localStack, thisIsCodeableConcept, checkDisplay, thisExtension, pct, mode) && ok; } else { - ok = validateElement(hostContext, errors, profile, checkDefn, null, null, resource, ei.getElement(), type, localStack, thisIsCodeableConcept, checkDisplay, thisExtension, pct, mode) && ok; + ok = validateElement(valContext, errors, profile, checkDefn, null, null, resource, ei.getElement(), type, localStack, thisIsCodeableConcept, checkDisplay, thisExtension, pct, mode) && ok; } } } @@ -6171,9 +6142,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return sd != null && sd.getKind().equals(StructureDefinitionKind.RESOURCE); } - private void trackUsage(StructureDefinition profile, ValidatorHostContext hostContext, Element element) { + private void trackUsage(StructureDefinition profile, ValidationContext valContext, Element element) { if (tracker != null) { - tracker.recordProfileUsage(profile, hostContext.getAppContext(), element); + tracker.recordProfileUsage(profile, valContext.getAppContext(), element); } } @@ -6278,7 +6249,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return ok; } - public List assignChildren(ValidatorHostContext hostContext, List errors, StructureDefinition profile, Element resource, + public List assignChildren(ValidationContext valContext, List errors, StructureDefinition profile, Element resource, NodeStack stack, SourcedChildDefinitions childDefinitions, List children, BooleanHolder bh) throws DefinitionException { // 2. assign children to a definition // for each definition, for each child, check whether it belongs in the slice @@ -6317,7 +6288,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (ei.sliceInfo == null) { ei.sliceInfo = new ArrayList<>(); } - unsupportedSlicing = matchSlice(hostContext, errors, ei.sliceInfo, profile, stack, slicer, unsupportedSlicing, problematicPaths, sliceOffset, i, ed, childUnsupportedSlicing, ei, bh); + unsupportedSlicing = matchSlice(valContext, errors, ei.sliceInfo, profile, stack, slicer, unsupportedSlicing, problematicPaths, sliceOffset, i, ed, childUnsupportedSlicing, ei, bh); } } int last = -1; @@ -6389,11 +6360,11 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return children; } - public boolean checkInvariants(ValidatorHostContext hostContext, List errors, StructureDefinition profile, ElementDefinition definition, Element resource, Element element, NodeStack stack, boolean onlyNonInherited) throws FHIRException { - return checkInvariants(hostContext, errors, stack.getLiteralPath(), profile, definition, null, null, resource, element, onlyNonInherited); + public boolean checkInvariants(ValidationContext valContext, List errors, StructureDefinition profile, ElementDefinition definition, Element resource, Element element, NodeStack stack, boolean onlyNonInherited) throws FHIRException { + return checkInvariants(valContext, errors, stack.getLiteralPath(), profile, definition, null, null, resource, element, onlyNonInherited); } - public boolean matchSlice(ValidatorHostContext hostContext, List errors, List sliceInfo, StructureDefinition profile, NodeStack stack, + public boolean matchSlice(ValidationContext valContext, List errors, List sliceInfo, StructureDefinition profile, NodeStack stack, ElementDefinition slicer, boolean unsupportedSlicing, List problematicPaths, int sliceOffset, int i, ElementDefinition ed, boolean childUnsupportedSlicing, ElementInfo ei, BooleanHolder bh) { boolean match = false; @@ -6403,7 +6374,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (nameMatches(ei.getName(), tail(ed.getPath()))) try { // System.out.println("match slices for "+stack.getLiteralPath()+": "+slicer.getId()+" = "+slicingSummary(slicer.getSlicing())); - match = sliceMatches(hostContext, ei.getElement(), ei.getPath(), slicer, ed, profile, errors, sliceInfo, stack, profile); + match = sliceMatches(valContext, ei.getElement(), ei.getPath(), slicer, ed, profile, errors, sliceInfo, stack, profile); if (match) { ei.slice = slicer; @@ -6522,7 +6493,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return IdStatus.REQUIRED; } - private boolean checkInvariants(ValidatorHostContext hostContext, List errors, String path, StructureDefinition profile, ElementDefinition ed, String typename, String typeProfile, Element resource, Element element, boolean onlyNonInherited) throws FHIRException, FHIRException { + private boolean checkInvariants(ValidationContext valContext, List errors, String path, StructureDefinition profile, ElementDefinition ed, String typename, String typeProfile, Element resource, Element element, boolean onlyNonInherited) throws FHIRException, FHIRException { if (noInvariantChecks) { return true; } @@ -6543,7 +6514,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (!invMap.keySet().contains(key)) { invErrors = new ArrayList(); invMap.put(key, invErrors); - ok = checkInvariant(hostContext, invErrors, path, profile, resource, element, inv) && ok; + ok = checkInvariant(valContext, invErrors, path, profile, resource, element, inv) && ok; } else { invErrors = (ArrayList)invMap.get(key); } @@ -6585,7 +6556,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return false; } - public boolean checkInvariant(ValidatorHostContext hostContext, List errors, String path, StructureDefinition profile, Element resource, Element element, ElementDefinitionConstraintComponent inv) throws FHIRException { + public boolean checkInvariant(ValidationContext valContext, List errors, String path, StructureDefinition profile, Element resource, Element element, ElementDefinitionConstraintComponent inv) throws FHIRException { if (IsExemptInvariant(path, element, inv)) { return true; } @@ -6611,7 +6582,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat String msg; try { long t = System.nanoTime(); - invOK = fpe.evaluateToBoolean(hostContext, resource, hostContext.getRootResource(), element, n); + invOK = fpe.evaluateToBoolean(valContext, resource, valContext.getRootResource(), element, n); timeTracker.fpe(t); msg = fpe.forLog(); } catch (Exception ex) { @@ -6677,7 +6648,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat /* * The actual base entry point for internal use (re-entrant) */ - private boolean validateResource(ValidatorHostContext hostContext, List errors, Element resource, + private boolean validateResource(ValidationContext valContext, List errors, Element resource, Element element, StructureDefinition defn, IdStatus idstatus, NodeStack stack, PercentageTracker pct, ValidationMode mode) throws FHIRException { boolean ok = true; @@ -6728,9 +6699,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } } // validate - if (rule(errors, NO_RULE_DATE, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), resourceName.equals(defn.getType()) || resourceName.equals(defn.getTypeTail()), I18nConstants.VALIDATION_VAL_PROFILE_WRONGTYPE, + if (rule(errors, NO_RULE_DATE, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), checkResourceName(defn, resourceName, element.getFormat()), I18nConstants.VALIDATION_VAL_PROFILE_WRONGTYPE, defn.getType(), resourceName, defn.getVersionedUrl())) { - ok = start(hostContext, errors, element, element, defn, stack, pct, mode) && ok; // root is both definition and type + ok = start(valContext, errors, element, element, defn, stack, pct, mode) && ok; // root is both definition and type } else { ok = false; } @@ -6741,6 +6712,22 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return ok; } + private boolean checkResourceName(StructureDefinition defn, String resourceName, FhirFormat format) { + if (resourceName.equals(defn.getType())) { + return true; + } + if (resourceName.equals(defn.getTypeTail())) { + return true; + } + if (format == FhirFormat.XML) { + String xn = ToolingExtensions.readStringExtension(defn, "http://hl7.org/fhir/StructureDefinition/elementdefinition-xml-name"); + if (resourceName.equals(xn)) { + return true; + } + } + return false; + } + private String errorIds(String path, boolean ok, List errors) { CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); for (ValidationMessage vm : errors) { diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/BundleValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/BundleValidator.java index a898da7c2..be6c06d62 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/BundleValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/BundleValidator.java @@ -28,7 +28,7 @@ import org.hl7.fhir.validation.instance.PercentageTracker; import org.hl7.fhir.validation.instance.utils.EntrySummary; import org.hl7.fhir.validation.instance.utils.IndexedElement; import org.hl7.fhir.validation.instance.utils.NodeStack; -import org.hl7.fhir.validation.instance.utils.ValidatorHostContext; +import org.hl7.fhir.validation.instance.utils.ValidationContext; public class BundleValidator extends BaseValidator { public final static String URI_REGEX3 = "((http|https)://([A-Za-z0-9\\\\\\.\\:\\%\\$]*\\/)*)?(Account|ActivityDefinition|AllergyIntolerance|AdverseEvent|Appointment|AppointmentResponse|AuditEvent|Basic|Binary|BodySite|Bundle|CapabilityStatement|CarePlan|CareTeam|ChargeItem|Claim|ClaimResponse|ClinicalImpression|CodeSystem|Communication|CommunicationRequest|CompartmentDefinition|Composition|ConceptMap|Condition (aka Problem)|Consent|Contract|Coverage|DataElement|DetectedIssue|Device|DeviceComponent|DeviceMetric|DeviceRequest|DeviceUseStatement|DiagnosticReport|DocumentManifest|DocumentReference|EligibilityRequest|EligibilityResponse|Encounter|Endpoint|EnrollmentRequest|EnrollmentResponse|EpisodeOfCare|ExpansionProfile|ExplanationOfBenefit|FamilyMemberHistory|Flag|Goal|GraphDefinition|Group|GuidanceResponse|HealthcareService|ImagingManifest|ImagingStudy|Immunization|ImmunizationRecommendation|ImplementationGuide|Library|Linkage|List|Location|Measure|MeasureReport|Media|Medication|MedicationAdministration|MedicationDispense|MedicationRequest|MedicationStatement|MessageDefinition|MessageHeader|NamingSystem|NutritionOrder|Observation|OperationDefinition|OperationOutcome|Organization|Parameters|Patient|PaymentNotice|PaymentReconciliation|Person|PlanDefinition|Practitioner|PractitionerRole|Procedure|ProcedureRequest|ProcessRequest|ProcessResponse|Provenance|Questionnaire|QuestionnaireResponse|ReferralRequest|RelatedPerson|RequestGroup|ResearchStudy|ResearchSubject|RiskAssessment|Schedule|SearchParameter|Sequence|ServiceDefinition|Slot|Specimen|StructureDefinition|StructureMap|Subscription|Substance|SupplyDelivery|SupplyRequest|Task|TestScript|TestReport|ValueSet|VisionPrescription)\\/[A-Za-z0-9\\-\\.]{1,64}(\\/_history\\/[A-Za-z0-9\\-\\.]{1,64})?"; @@ -39,7 +39,7 @@ public class BundleValidator extends BaseValidator { this.serverBase = serverBase; } - public boolean validateBundle(List errors, Element bundle, NodeStack stack, boolean checkSpecials, ValidatorHostContext hostContext, PercentageTracker pct, ValidationMode mode) { + public boolean validateBundle(List errors, Element bundle, NodeStack stack, boolean checkSpecials, ValidationContext hostContext, PercentageTracker pct, ValidationMode mode) { boolean ok = true; String type = bundle.getNamedChildValue(TYPE); type = StringUtils.defaultString(type); diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/MeasureValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/MeasureValidator.java index b4f690b36..af2628d76 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/MeasureValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/MeasureValidator.java @@ -33,7 +33,7 @@ import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; import org.hl7.fhir.utilities.xml.XMLUtil; import org.hl7.fhir.validation.BaseValidator; import org.hl7.fhir.validation.instance.utils.NodeStack; -import org.hl7.fhir.validation.instance.utils.ValidatorHostContext; +import org.hl7.fhir.validation.instance.utils.ValidationContext; import org.w3c.dom.Document; public class MeasureValidator extends BaseValidator { @@ -43,7 +43,7 @@ public class MeasureValidator extends BaseValidator { super(parent); } - public boolean validateMeasure(ValidatorHostContext hostContext, List errors, Element element, NodeStack stack) throws FHIRException { + public boolean validateMeasure(ValidationContext hostContext, List errors, Element element, NodeStack stack) throws FHIRException { boolean ok = true; MeasureContext mctxt = new MeasureContext(); List libs = element.getChildrenByName("library"); @@ -131,7 +131,7 @@ public class MeasureValidator extends BaseValidator { return ok; } - private boolean validateMeasureCriteria(ValidatorHostContext hostContext, List errors, MeasureContext mctxt, Element crit, NodeStack nsc) { + private boolean validateMeasureCriteria(ValidationContext hostContext, List errors, MeasureContext mctxt, Element crit, NodeStack nsc) { boolean ok = true; String mimeType = crit.getChildValue("language"); if (!Utilities.noString(mimeType)) { // that would be an error elsewhere @@ -206,7 +206,7 @@ public class MeasureValidator extends BaseValidator { // --------------------------------------------------------------------------------------------------------------------------------------------------------- - public boolean validateMeasureReport(ValidatorHostContext hostContext, List errors, Element element, NodeStack stack) throws FHIRException { + public boolean validateMeasureReport(ValidationContext hostContext, List errors, Element element, NodeStack stack) throws FHIRException { boolean ok = true; Element m = element.getNamedChild("measure"); String measure = null; @@ -282,7 +282,7 @@ public class MeasureValidator extends BaseValidator { } } - private boolean validateMeasureReportGroups(ValidatorHostContext hostContext, MeasureContext m, List errors, Element mr, NodeStack stack, boolean inProgress) { + private boolean validateMeasureReportGroups(ValidationContext hostContext, MeasureContext m, List errors, Element mr, NodeStack stack, boolean inProgress) { boolean ok = true; if (m.groups().size() == 0) { @@ -344,7 +344,7 @@ public class MeasureValidator extends BaseValidator { return "data-collection".equals(mr.getChildValue("type")); } - private boolean validateMeasureReportGroup(ValidatorHostContext hostContext, MeasureContext m, MeasureGroupComponent mg, List errors, Element mrg, NodeStack ns, boolean inProgress) { + private boolean validateMeasureReportGroup(ValidationContext hostContext, MeasureContext m, MeasureGroupComponent mg, List errors, Element mrg, NodeStack ns, boolean inProgress) { boolean ok = true; ok = validateMeasureReportGroupPopulations(hostContext, m, mg, errors, mrg, ns, inProgress) && ok; ok = validateScore(hostContext, m, errors, mrg, ns, inProgress) && ok; @@ -352,7 +352,7 @@ public class MeasureValidator extends BaseValidator { return ok; } - private boolean validateScore(ValidatorHostContext hostContext, MeasureContext m, List errors, Element mrg, NodeStack stack, boolean inProgress) { + private boolean validateScore(ValidationContext hostContext, MeasureContext m, List errors, Element mrg, NodeStack stack, boolean inProgress) { boolean ok = true; Element ms = mrg.getNamedChild("measureScore"); @@ -456,7 +456,7 @@ public class MeasureValidator extends BaseValidator { return true; } } - private boolean validateMeasureReportGroupPopulations(ValidatorHostContext hostContext, MeasureContext m, MeasureGroupComponent mg, List errors, Element mrg, NodeStack stack, boolean inProgress) { + private boolean validateMeasureReportGroupPopulations(ValidationContext hostContext, MeasureContext m, MeasureGroupComponent mg, List errors, Element mrg, NodeStack stack, boolean inProgress) { boolean ok = true; // there must be a population for each population defined in the measure, and no 4others. List pops = new ArrayList(); @@ -491,7 +491,7 @@ public class MeasureValidator extends BaseValidator { return ok; } - private boolean validateMeasureReportGroupPopulation(ValidatorHostContext hostContext, MeasureContext m, MeasureGroupPopulationComponent mgp, List errors, Element mrgp, NodeStack ns, boolean inProgress) { + private boolean validateMeasureReportGroupPopulation(ValidationContext hostContext, MeasureContext m, MeasureGroupPopulationComponent mgp, List errors, Element mrgp, NodeStack ns, boolean inProgress) { boolean ok = true; List sr = mrgp.getChildrenByName("subjectResults"); if ("subject-list".equals(m.reportType())) { @@ -508,7 +508,7 @@ public class MeasureValidator extends BaseValidator { return ok; } - private boolean validateMeasureReportGroupStratifiers(ValidatorHostContext hostContext, MeasureContext m, MeasureGroupComponent mg, List errors, Element mrg, NodeStack stack, boolean inProgress) { + private boolean validateMeasureReportGroupStratifiers(ValidationContext hostContext, MeasureContext m, MeasureGroupComponent mg, List errors, Element mrg, NodeStack stack, boolean inProgress) { boolean ok = true; // there must be a population for each population defined in the measure, and no 4others. @@ -544,7 +544,7 @@ public class MeasureValidator extends BaseValidator { return true; } - private boolean validateMeasureReportGroupStratifier(ValidatorHostContext hostContext, MeasureContext m, MeasureGroupStratifierComponent mgs, List errors, Element mrgs, NodeStack ns, boolean inProgress) { + private boolean validateMeasureReportGroupStratifier(ValidationContext hostContext, MeasureContext m, MeasureGroupStratifierComponent mgs, List errors, Element mrgs, NodeStack ns, boolean inProgress) { // still to be done return true; } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/QuestionnaireValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/QuestionnaireValidator.java index 5499a3005..3f8d349be 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/QuestionnaireValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/QuestionnaireValidator.java @@ -38,10 +38,10 @@ import org.hl7.fhir.utilities.validation.ValidationMessage.Source; import org.hl7.fhir.utilities.validation.ValidationOptions; import org.hl7.fhir.validation.BaseValidator; import org.hl7.fhir.validation.cli.utils.QuestionnaireMode; -import org.hl7.fhir.validation.instance.EnableWhenEvaluator; -import org.hl7.fhir.validation.instance.EnableWhenEvaluator.QStack; +import org.hl7.fhir.validation.instance.utils.EnableWhenEvaluator; import org.hl7.fhir.validation.instance.utils.NodeStack; -import org.hl7.fhir.validation.instance.utils.ValidatorHostContext; +import org.hl7.fhir.validation.instance.utils.ValidationContext; +import org.hl7.fhir.validation.instance.utils.EnableWhenEvaluator.QStack; import ca.uhn.fhir.util.ObjectUtil; @@ -431,7 +431,7 @@ public class QuestionnaireValidator extends BaseValidator { return list; } - public boolean validateQuestionannaireResponse(ValidatorHostContext hostContext, List errors, Element element, NodeStack stack) throws FHIRException { + public boolean validateQuestionannaireResponse(ValidationContext hostContext, List errors, Element element, NodeStack stack) throws FHIRException { if (questionnaireMode == QuestionnaireMode.NONE) { return true; } @@ -481,7 +481,7 @@ public class QuestionnaireValidator extends BaseValidator { return ok; } - private boolean validateQuestionnaireResponseItem(ValidatorHostContext hostContext, QuestionnaireWithContext qsrc, QuestionnaireItemComponent qItem, List errors, Element element, NodeStack stack, boolean inProgress, Element questionnaireResponseRoot, QStack qstack) { + private boolean validateQuestionnaireResponseItem(ValidationContext hostContext, QuestionnaireWithContext qsrc, QuestionnaireItemComponent qItem, List errors, Element element, NodeStack stack, boolean inProgress, Element questionnaireResponseRoot, QStack qstack) { BooleanHolder ok = new BooleanHolder(); String text = element.getNamedChildValue("text"); @@ -608,7 +608,7 @@ public class QuestionnaireValidator extends BaseValidator { return !answers.isEmpty() || !qItem.getRequired() || qItem.getType() == QuestionnaireItemType.GROUP; } - private boolean validateQuestionnaireResponseItem(ValidatorHostContext hostcontext, QuestionnaireWithContext qsrc, QuestionnaireItemComponent qItem, List errors, List elements, NodeStack stack, boolean inProgress, Element questionnaireResponseRoot, QStack qstack) { + private boolean validateQuestionnaireResponseItem(ValidationContext hostcontext, QuestionnaireWithContext qsrc, QuestionnaireItemComponent qItem, List errors, List elements, NodeStack stack, boolean inProgress, Element questionnaireResponseRoot, QStack qstack) { boolean ok = true; if (elements.size() > 1) { ok = rulePlural(errors, NO_RULE_DATE, IssueType.INVALID, elements.get(1).getElement().line(), elements.get(1).getElement().col(), stack.getLiteralPath(), qItem.getRepeats(), elements.size(), I18nConstants.QUESTIONNAIRE_QR_ITEM_ONLYONEI, qItem.getLinkId()) && ok; @@ -628,7 +628,7 @@ public class QuestionnaireValidator extends BaseValidator { return -1; } - private boolean validateQuestionannaireResponseItems(ValidatorHostContext hostContext, QuestionnaireWithContext qsrc, List qItems, List errors, Element element, NodeStack stack, boolean inProgress, Element questionnaireResponseRoot, QStack qstack) { + private boolean validateQuestionannaireResponseItems(ValidationContext hostContext, QuestionnaireWithContext qsrc, List qItems, List errors, Element element, NodeStack stack, boolean inProgress, Element questionnaireResponseRoot, QStack qstack) { boolean ok = true; List items = new ArrayList(); element.getNamedChildren("item", items); @@ -673,7 +673,7 @@ public class QuestionnaireValidator extends BaseValidator { return ok; } - public boolean validateQuestionnaireResponseItem(ValidatorHostContext hostContext, QuestionnaireWithContext qsrc, List errors, Element element, NodeStack stack, boolean inProgress, Element questionnaireResponseRoot, QuestionnaireItemComponent qItem, List mapItem, QStack qstack) { + public boolean validateQuestionnaireResponseItem(ValidationContext hostContext, QuestionnaireWithContext qsrc, List errors, Element element, NodeStack stack, boolean inProgress, Element questionnaireResponseRoot, QuestionnaireItemComponent qItem, List mapItem, QStack qstack) { boolean ok = true; boolean enabled = myEnableWhenEvaluator.isQuestionEnabled(hostContext, qItem, qstack, fpe); if (mapItem != null) { diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/CanonicalResourceLookupResult.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/CanonicalResourceLookupResult.java new file mode 100644 index 000000000..dbf45b7cf --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/CanonicalResourceLookupResult.java @@ -0,0 +1,27 @@ +package org.hl7.fhir.validation.instance.utils; + +import org.hl7.fhir.r5.model.CanonicalResource; + +public class CanonicalResourceLookupResult { + + CanonicalResource resource; + String error; + + public CanonicalResourceLookupResult(CanonicalResource resource) { + this.resource = resource; + } + + public CanonicalResourceLookupResult(String error) { + this.error = error; + } + + public CanonicalResource getResource() { + return resource; + } + + public String getError() { + return error; + } + + +} \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/CanonicalTypeSorter.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/CanonicalTypeSorter.java new file mode 100644 index 000000000..1df1b64e0 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/CanonicalTypeSorter.java @@ -0,0 +1,14 @@ +package org.hl7.fhir.validation.instance.utils; + +import java.util.Comparator; + +import org.hl7.fhir.r5.model.CanonicalType; + +public class CanonicalTypeSorter implements Comparator { + + @Override + public int compare(CanonicalType o1, CanonicalType o2) { + return o1.getValue().compareTo(o2.getValue()); + } + +} \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/EnableWhenEvaluator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/EnableWhenEvaluator.java similarity index 98% rename from org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/EnableWhenEvaluator.java rename to org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/EnableWhenEvaluator.java index 824c31e3c..ea945495f 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/EnableWhenEvaluator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/EnableWhenEvaluator.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.validation.instance; +package org.hl7.fhir.validation.instance.utils; /* Copyright (c) 2011+, HL7, Inc. @@ -48,7 +48,6 @@ import org.hl7.fhir.r5.model.Questionnaire.QuestionnaireItemEnableWhenComponent; import org.hl7.fhir.r5.model.Questionnaire.QuestionnaireItemOperator; import org.hl7.fhir.r5.utils.FHIRPathEngine; import org.hl7.fhir.validation.instance.type.QuestionnaireValidator.QuestionnaireWithContext; -import org.hl7.fhir.validation.instance.utils.ValidatorHostContext; import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; @@ -144,7 +143,7 @@ public class EnableWhenEvaluator { *

* The context Questionnaire and QuestionnaireResponse are always available */ - public boolean isQuestionEnabled(ValidatorHostContext hostContext, QuestionnaireItemComponent qitem, QStack qstack, FHIRPathEngine engine) { + public boolean isQuestionEnabled(ValidationContext hostContext, QuestionnaireItemComponent qitem, QStack qstack, FHIRPathEngine engine) { if (hasExpressionExtension(qitem)) { String expr = getExpression(qitem); ExpressionNode node = engine.parse(expr); diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/ResolvedReference.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/ResolvedReference.java index eb706982a..18c3a010a 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/ResolvedReference.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/ResolvedReference.java @@ -50,11 +50,11 @@ public class ResolvedReference { return focus; } - public ValidatorHostContext hostContext(ValidatorHostContext hostContext, StructureDefinition profile) { + public ValidationContext valContext(ValidationContext valContext, StructureDefinition profile) { if (external) { - return hostContext.forRemoteReference(profile, resource); + return valContext.forRemoteReference(profile, resource); } else { - return hostContext.forLocalReference(profile, resource); + return valContext.forLocalReference(profile, resource); } } } \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/StructureDefinitionSorterByUrl.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/StructureDefinitionSorterByUrl.java new file mode 100644 index 000000000..39b19fb2c --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/StructureDefinitionSorterByUrl.java @@ -0,0 +1,14 @@ +package org.hl7.fhir.validation.instance.utils; + +import java.util.Comparator; + +import org.hl7.fhir.r5.model.StructureDefinition; + +public class StructureDefinitionSorterByUrl implements Comparator { + + @Override + public int compare(StructureDefinition o1, StructureDefinition o2) { + return o1.getUrl().compareTo(o2.getUrl()); + } + +} \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/ValidatorHostContext.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/ValidationContext.java similarity index 69% rename from org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/ValidatorHostContext.java rename to org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/ValidationContext.java index 3f152ba8c..b2acb49e8 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/ValidatorHostContext.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/ValidationContext.java @@ -5,13 +5,18 @@ import java.util.List; import java.util.Map; import org.hl7.fhir.r5.elementmodel.Element; +import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.utilities.validation.ValidationMessage; -public class ValidatorHostContext { +public class ValidationContext { private Object appContext; + // the version we are currently validating for right now + // not implemented yet - this is the forerunner of a major upgrade to the validator + private String version; + // the resource we are actually validating right now private Element resource; // the resource that is the scope of id resolution - either the same as resource, or the resource the contains that resource. This can only be one level deep. @@ -19,14 +24,15 @@ public class ValidatorHostContext { private Element groupingResource; // either a bundle or a parameters that holds the rootResource (for reference resolution) private StructureDefinition profile; // the profile that contains the content being validated + private boolean checkSpecials = true; private Map> sliceRecords; - - public ValidatorHostContext(Object appContext) { + + public ValidationContext(Object appContext) { this.appContext = appContext; } - public ValidatorHostContext(Object appContext, Element element) { + public ValidationContext(Object appContext, Element element) { this.appContext = appContext; this.resource = element; this.rootResource = element; @@ -42,7 +48,7 @@ public class ValidatorHostContext { } } - public ValidatorHostContext(Object appContext, Element element, Element root) { + public ValidationContext(Object appContext, Element element, Element root) { this.appContext = appContext; this.resource = element; this.rootResource = root; @@ -51,7 +57,7 @@ public class ValidatorHostContext { dump("creating"); } - public ValidatorHostContext(Object appContext, Element element, Element root, Element groupingResource) { + public ValidationContext(Object appContext, Element element, Element root, Element groupingResource) { this.appContext = appContext; this.resource = element; this.rootResource = root; @@ -64,12 +70,12 @@ public class ValidatorHostContext { return appContext; } - public ValidatorHostContext setAppContext(Object appContext) { + public ValidationContext setAppContext(Object appContext) { this.appContext = appContext; return this; } - public ValidatorHostContext setResource(Element resource) { + public ValidationContext setResource(Element resource) { this.resource = resource; return this; } @@ -78,7 +84,7 @@ public class ValidatorHostContext { return rootResource; } - public ValidatorHostContext setRootResource(Element rootResource) { + public ValidationContext setRootResource(Element rootResource) { this.rootResource = rootResource; dump("setting root resource"); return this; @@ -92,7 +98,7 @@ public class ValidatorHostContext { return profile; } - public ValidatorHostContext setProfile(StructureDefinition profile) { + public ValidationContext setProfile(StructureDefinition profile) { this.profile = profile; return this; } @@ -101,7 +107,7 @@ public class ValidatorHostContext { return sliceRecords; } - public ValidatorHostContext setSliceRecords(Map> sliceRecords) { + public ValidationContext setSliceRecords(Map> sliceRecords) { this.sliceRecords = sliceRecords; return this; } @@ -124,45 +130,49 @@ public class ValidatorHostContext { } } - public ValidatorHostContext forContained(Element element) { - ValidatorHostContext res = new ValidatorHostContext(appContext); + public ValidationContext forContained(Element element) { + ValidationContext res = new ValidationContext(appContext); res.rootResource = resource; res.resource = element; res.profile = profile; res.groupingResource = groupingResource; + res.version = version; res.dump("forContained"); return res; } - public ValidatorHostContext forEntry(Element element, Element groupingResource) { - ValidatorHostContext res = new ValidatorHostContext(appContext); + public ValidationContext forEntry(Element element, Element groupingResource) { + ValidationContext res = new ValidationContext(appContext); res.rootResource = element; res.resource = element; res.profile = profile; res.groupingResource = groupingResource; + res.version = version; res.dump("forEntry"); return res; } - public ValidatorHostContext forProfile(StructureDefinition profile) { - ValidatorHostContext res = new ValidatorHostContext(appContext); + public ValidationContext forProfile(StructureDefinition profile) { + ValidationContext res = new ValidationContext(appContext); res.resource = resource; res.rootResource = rootResource; res.profile = profile; + res.version = version; res.groupingResource = groupingResource; res.sliceRecords = sliceRecords != null ? sliceRecords : new HashMap>(); res.dump("forProfile "+profile.getUrl()); return res; } - public ValidatorHostContext forLocalReference(StructureDefinition profile, Element resource) { - ValidatorHostContext res = new ValidatorHostContext(appContext); + public ValidationContext forLocalReference(StructureDefinition profile, Element resource) { + ValidationContext res = new ValidationContext(appContext); res.resource = resource; res.rootResource = resource; res.profile = profile; res.groupingResource = groupingResource; res.checkSpecials = false; res.dump("forLocalReference "+profile.getUrl()); + res.version = version; return res; } @@ -173,28 +183,39 @@ public class ValidatorHostContext { // } } - public ValidatorHostContext forRemoteReference(StructureDefinition profile, Element resource) { - ValidatorHostContext res = new ValidatorHostContext(appContext); + public ValidationContext forRemoteReference(StructureDefinition profile, Element resource) { + ValidationContext res = new ValidationContext(appContext); res.resource = resource; res.rootResource = resource; res.profile = profile; res.groupingResource = null; res.checkSpecials = false; + res.version = version; res.dump("forRemoteReference "+profile.getUrl()); return res; } - public ValidatorHostContext forSlicing() { - ValidatorHostContext res = new ValidatorHostContext(appContext); + public ValidationContext forSlicing() { + ValidationContext res = new ValidationContext(appContext); res.resource = resource; res.rootResource = resource; res.groupingResource = groupingResource; res.profile = profile; res.checkSpecials = false; + res.version = version; res.sliceRecords = new HashMap>(); res.dump("forSlicing"); return res; } + public String getVersion() { + return version; + } + + public ValidationContext setVersion(String version) { + this.version = version; + return this; + } + } \ No newline at end of file