Merge branch 'master' of https://github.com/hapifhir/org.hl7.fhir.core into grahame_work
This commit is contained in:
commit
82a4c02a8f
|
@ -21,7 +21,6 @@ package org.hl7.fhir.r5.validation;
|
|||
*/
|
||||
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.*;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
|
@ -29,7 +28,7 @@ import org.hl7.fhir.r5.elementmodel.Element;
|
|||
import org.hl7.fhir.r5.model.*;
|
||||
import org.hl7.fhir.r5.model.Questionnaire.*;
|
||||
import org.hl7.fhir.r5.utils.FHIRPathEngine;
|
||||
import org.hl7.fhir.r5.validation.InstanceValidator.ValidatorHostContext;
|
||||
import org.hl7.fhir.r5.validation.instancevalidator.utils.ValidatorHostContext;
|
||||
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -22,6 +22,7 @@ import org.hl7.fhir.r5.terminologies.ConceptMapEngine;
|
|||
import org.hl7.fhir.r5.utils.*;
|
||||
import org.hl7.fhir.r5.utils.IResourceValidator.*;
|
||||
import org.hl7.fhir.r5.utils.StructureMapUtilities.ITransformerServices;
|
||||
import org.hl7.fhir.r5.validation.instancevalidator.InstanceValidator;
|
||||
import org.hl7.fhir.utilities.IniFile;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,4 @@
|
|||
package org.hl7.fhir.r5.validation;
|
||||
package org.hl7.fhir.r5.validation.instancevalidator;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
package org.hl7.fhir.r5.validation.instancevalidator.utils;
|
||||
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
import org.hl7.fhir.r5.validation.instancevalidator.InstanceValidator;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
|
||||
public class ChildIterator {
|
||||
private final InstanceValidator instanceValidator;
|
||||
private String basePath;
|
||||
private Element parent;
|
||||
private int cursor;
|
||||
private int lastCount;
|
||||
|
||||
public ChildIterator(InstanceValidator instanceValidator, String path, Element element) {
|
||||
this.instanceValidator = instanceValidator;
|
||||
parent = element;
|
||||
basePath = path;
|
||||
cursor = -1;
|
||||
}
|
||||
|
||||
public InstanceValidator getInstanceValidator() {
|
||||
return instanceValidator;
|
||||
}
|
||||
|
||||
public String getBasePath() {
|
||||
return basePath;
|
||||
}
|
||||
|
||||
public ChildIterator setBasePath(String basePath) {
|
||||
this.basePath = basePath;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Element getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public ChildIterator setParent(Element parent) {
|
||||
this.parent = parent;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getCursor() {
|
||||
return cursor;
|
||||
}
|
||||
|
||||
public ChildIterator setCursor(int cursor) {
|
||||
this.cursor = cursor;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getLastCount() {
|
||||
return lastCount;
|
||||
}
|
||||
|
||||
public ChildIterator setLastCount(int lastCount) {
|
||||
this.lastCount = lastCount;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Element element() {
|
||||
return parent.getChildren().get(cursor);
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return element().getName();
|
||||
}
|
||||
|
||||
public int count() {
|
||||
String nb = cursor == 0 ? "--" : parent.getChildren().get(cursor - 1).getName();
|
||||
String na = cursor >= parent.getChildren().size() - 1 ? "--" : parent.getChildren().get(cursor + 1).getName();
|
||||
if (name().equals(nb) || name().equals(na)) {
|
||||
return lastCount;
|
||||
} else
|
||||
return -1;
|
||||
}
|
||||
|
||||
public boolean next() {
|
||||
if (cursor == -1) {
|
||||
cursor++;
|
||||
lastCount = 0;
|
||||
} else {
|
||||
String lastName = name();
|
||||
cursor++;
|
||||
if (cursor < parent.getChildren().size() && name().equals(lastName))
|
||||
lastCount++;
|
||||
else
|
||||
lastCount = 0;
|
||||
}
|
||||
return cursor < parent.getChildren().size();
|
||||
}
|
||||
|
||||
public String path() {
|
||||
int i = count();
|
||||
String sfx = "";
|
||||
String n = name();
|
||||
String fn = "";
|
||||
if (element().getProperty().isChoice()) {
|
||||
String en = element().getProperty().getName();
|
||||
en = en.substring(0, en.length() - 3);
|
||||
String t = n.substring(en.length());
|
||||
if (instanceValidator.isPrimitiveType(Utilities.uncapitalize(t)))
|
||||
t = Utilities.uncapitalize(t);
|
||||
n = en;
|
||||
fn = ".ofType(" + t + ")";
|
||||
}
|
||||
if (i > -1 || (element().getSpecial() == null && element().isList())) {
|
||||
sfx = "[" + Integer.toString(lastCount) + "]";
|
||||
}
|
||||
return basePath + "." + n + sfx + fn;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
package org.hl7.fhir.r5.validation.instancevalidator.utils;
|
||||
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
import org.hl7.fhir.r5.model.ElementDefinition;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ElementInfo {
|
||||
|
||||
public List<ValidationMessage> sliceInfo;
|
||||
public int index; // order of definition in overall order. all slices get the index of the slicing definition
|
||||
public int sliceindex; // order of the definition in the slices (if slice != null)
|
||||
public int count;
|
||||
public ElementDefinition definition;
|
||||
public ElementDefinition slice;
|
||||
public boolean additionalSlice; // If true, indicates that this element is an additional slice
|
||||
private Element element;
|
||||
private String name;
|
||||
private String path;
|
||||
|
||||
public ElementInfo(String name, Element element, String path, int count) {
|
||||
this.name = name;
|
||||
this.element = element;
|
||||
this.path = path;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public List<ValidationMessage> getSliceInfo() {
|
||||
return sliceInfo;
|
||||
}
|
||||
|
||||
public ElementInfo setSliceInfo(List<ValidationMessage> sliceInfo) {
|
||||
this.sliceInfo = sliceInfo;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public ElementInfo setIndex(int index) {
|
||||
this.index = index;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getSliceindex() {
|
||||
return sliceindex;
|
||||
}
|
||||
|
||||
public ElementInfo setSliceindex(int sliceindex) {
|
||||
this.sliceindex = sliceindex;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public ElementInfo setCount(int count) {
|
||||
this.count = count;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ElementDefinition getDefinition() {
|
||||
return definition;
|
||||
}
|
||||
|
||||
public ElementInfo setDefinition(ElementDefinition definition) {
|
||||
this.definition = definition;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ElementDefinition getSlice() {
|
||||
return slice;
|
||||
}
|
||||
|
||||
public ElementInfo setSlice(ElementDefinition slice) {
|
||||
this.slice = slice;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isAdditionalSlice() {
|
||||
return additionalSlice;
|
||||
}
|
||||
|
||||
public ElementInfo setAdditionalSlice(boolean additionalSlice) {
|
||||
this.additionalSlice = additionalSlice;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Element getElement() {
|
||||
return element;
|
||||
}
|
||||
|
||||
public ElementInfo setElement(Element element) {
|
||||
this.element = element;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public ElementInfo setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public ElementInfo setPath(String path) {
|
||||
this.path = path;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int col() {
|
||||
return element.col();
|
||||
}
|
||||
|
||||
public int line() {
|
||||
return element.line();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return path;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package org.hl7.fhir.r5.validation.instancevalidator.utils;
|
||||
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
import org.hl7.fhir.r5.validation.instancevalidator.InstanceValidator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class EntrySummary {
|
||||
|
||||
Element entry;
|
||||
Element resource;
|
||||
List<EntrySummary> targets = new ArrayList<>();
|
||||
|
||||
public Element getEntry() {
|
||||
return entry;
|
||||
}
|
||||
|
||||
public EntrySummary setEntry(Element entry) {
|
||||
this.entry = entry;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Element getResource() {
|
||||
return resource;
|
||||
}
|
||||
|
||||
public EntrySummary setResource(Element resource) {
|
||||
this.resource = resource;
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<EntrySummary> getTargets() {
|
||||
return targets;
|
||||
}
|
||||
|
||||
public EntrySummary setTargets(List<EntrySummary> targets) {
|
||||
this.targets = targets;
|
||||
return this;
|
||||
}
|
||||
|
||||
public EntrySummary(Element entry, Element resource) {
|
||||
this.entry = entry;
|
||||
this.resource = resource;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package org.hl7.fhir.r5.validation.instancevalidator.utils;
|
||||
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
|
||||
public class IndexedElement {
|
||||
private int index;
|
||||
private Element match;
|
||||
private Element entry;
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public IndexedElement setIndex(int index) {
|
||||
this.index = index;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Element getMatch() {
|
||||
return match;
|
||||
}
|
||||
|
||||
public IndexedElement setMatch(Element match) {
|
||||
this.match = match;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Element getEntry() {
|
||||
return entry;
|
||||
}
|
||||
|
||||
public IndexedElement setEntry(Element entry) {
|
||||
this.entry = entry;
|
||||
return this;
|
||||
}
|
||||
|
||||
public IndexedElement(int index, Element match, Element entry) {
|
||||
super();
|
||||
this.index = index;
|
||||
this.match = match;
|
||||
this.entry = entry;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package org.hl7.fhir.r5.validation.instancevalidator.utils;
|
||||
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
import org.hl7.fhir.r5.validation.instancevalidator.InstanceValidator;
|
||||
|
||||
public class ResolvedReference {
|
||||
|
||||
private Element resource;
|
||||
private Element focus;
|
||||
private boolean external;
|
||||
private InstanceValidator.NodeStack stack;
|
||||
|
||||
public ResolvedReference setResource(Element resource) {
|
||||
this.resource = resource;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Element getResource() {
|
||||
return resource;
|
||||
}
|
||||
|
||||
public ResolvedReference setFocus(Element focus) {
|
||||
this.focus = focus;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isExternal() {
|
||||
return external;
|
||||
}
|
||||
|
||||
public ResolvedReference setExternal(boolean external) {
|
||||
this.external = external;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ResolvedReference setStack(InstanceValidator.NodeStack stack) {
|
||||
this.stack = stack;
|
||||
return this;
|
||||
}
|
||||
|
||||
public InstanceValidator.NodeStack getStack() {
|
||||
return stack;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return focus.fhirType();
|
||||
}
|
||||
|
||||
public Element getFocus() {
|
||||
return focus;
|
||||
}
|
||||
|
||||
public ValidatorHostContext hostContext(ValidatorHostContext hostContext, StructureDefinition profile) {
|
||||
if (external) {
|
||||
return hostContext.forRemoteReference(profile, resource);
|
||||
} else {
|
||||
return hostContext.forLocalReference(profile, resource);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package org.hl7.fhir.r5.validation.instancevalidator.utils;
|
||||
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The validator keeps one of these classes for each resource it validates (e.g. when chasing references)
|
||||
* <p>
|
||||
* It keeps track of the state of resource validation - a given resrouce may be validated agaisnt multiple
|
||||
* profiles during a single validation, and it may be valid against some, and invalid against others.
|
||||
* <p>
|
||||
* We don't want to keep doing the same validation, so we remember the outcomes for each combination
|
||||
* of resource + profile
|
||||
* <p>
|
||||
* Additionally, profile validation may be circular - e.g. a Patient profile that applies the same profile
|
||||
* to linked patients, and 2 patient resources that link to each other. So this class also tracks validation
|
||||
* in process.
|
||||
* <p>
|
||||
* If the validator comes back to the same point, and validates the same instance against the same profile
|
||||
* while it's already validating, it assumes it's valid - it cannot have new errors that wouldn't already
|
||||
* be found in the first iteration - in other words, there's no errors
|
||||
*
|
||||
* @author graha
|
||||
*/
|
||||
public class ResourceValidationTracker {
|
||||
private Map<String, List<ValidationMessage>> validations = new HashMap<>();
|
||||
|
||||
public void startValidating(StructureDefinition sd) {
|
||||
validations.put(sd.getUrl(), new ArrayList<ValidationMessage>());
|
||||
}
|
||||
|
||||
public List<ValidationMessage> getOutcomes(StructureDefinition sd) {
|
||||
return validations.get(sd.getUrl());
|
||||
}
|
||||
|
||||
public void storeOutcomes(StructureDefinition sd, List<ValidationMessage> errors) {
|
||||
validations.put(sd.getUrl(), errors);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
package org.hl7.fhir.r5.validation.instancevalidator.utils;
|
||||
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ValidatorHostContext {
|
||||
|
||||
private Object appContext;
|
||||
private Element container; // bundle, or parameters
|
||||
private Element resource;
|
||||
private Element rootResource;
|
||||
private StructureDefinition profile; // the profile that contains the content being validated
|
||||
private boolean checkSpecials = true;
|
||||
private Map<String, List<ValidationMessage>> sliceRecords;
|
||||
|
||||
public ValidatorHostContext(Object appContext) {
|
||||
this.appContext = appContext;
|
||||
}
|
||||
|
||||
public ValidatorHostContext(Object appContext, Element element) {
|
||||
this.appContext = appContext;
|
||||
this.resource = element;
|
||||
this.rootResource = element;
|
||||
}
|
||||
|
||||
public Object getAppContext() {
|
||||
return appContext;
|
||||
}
|
||||
|
||||
public ValidatorHostContext setAppContext(Object appContext) {
|
||||
this.appContext = appContext;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Element getContainer() {
|
||||
return container;
|
||||
}
|
||||
|
||||
public ValidatorHostContext setContainer(Element container) {
|
||||
this.container = container;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ValidatorHostContext setResource(Element resource) {
|
||||
this.resource = resource;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Element getRootResource() {
|
||||
return rootResource;
|
||||
}
|
||||
|
||||
public ValidatorHostContext setRootResource(Element rootResource) {
|
||||
this.rootResource = rootResource;
|
||||
return this;
|
||||
}
|
||||
|
||||
public StructureDefinition getProfile() {
|
||||
return profile;
|
||||
}
|
||||
|
||||
public ValidatorHostContext setProfile(StructureDefinition profile) {
|
||||
this.profile = profile;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Map<String, List<ValidationMessage>> getSliceRecords() {
|
||||
return sliceRecords;
|
||||
}
|
||||
|
||||
public ValidatorHostContext setSliceRecords(Map<String, List<ValidationMessage>> sliceRecords) {
|
||||
this.sliceRecords = sliceRecords;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isCheckSpecials() {
|
||||
return checkSpecials;
|
||||
}
|
||||
|
||||
public void setCheckSpecials(boolean checkSpecials) {
|
||||
this.checkSpecials = checkSpecials;
|
||||
}
|
||||
|
||||
public Element getResource() {
|
||||
return resource;
|
||||
}
|
||||
|
||||
public void sliceNotes(String url, List<ValidationMessage> record) {
|
||||
sliceRecords.put(url, record);
|
||||
}
|
||||
|
||||
public ValidatorHostContext forContained(Element element) {
|
||||
ValidatorHostContext res = new ValidatorHostContext(appContext);
|
||||
res.rootResource = resource;
|
||||
res.resource = element;
|
||||
res.container = resource;
|
||||
res.profile = profile;
|
||||
return res;
|
||||
}
|
||||
|
||||
public ValidatorHostContext forEntry(Element element) {
|
||||
ValidatorHostContext res = new ValidatorHostContext(appContext);
|
||||
res.rootResource = element;
|
||||
res.resource = element;
|
||||
res.container = resource;
|
||||
res.profile = profile;
|
||||
return res;
|
||||
}
|
||||
|
||||
public ValidatorHostContext forProfile(StructureDefinition profile) {
|
||||
ValidatorHostContext res = new ValidatorHostContext(appContext);
|
||||
res.resource = resource;
|
||||
res.rootResource = rootResource;
|
||||
res.container = container;
|
||||
res.profile = profile;
|
||||
res.sliceRecords = sliceRecords != null ? sliceRecords : new HashMap<String, List<ValidationMessage>>();
|
||||
return res;
|
||||
}
|
||||
|
||||
public ValidatorHostContext forLocalReference(StructureDefinition profile, Element resource) {
|
||||
ValidatorHostContext res = new ValidatorHostContext(appContext);
|
||||
res.resource = resource;
|
||||
res.rootResource = resource;
|
||||
res.container = container;
|
||||
res.profile = profile;
|
||||
res.checkSpecials = false;
|
||||
return res;
|
||||
}
|
||||
|
||||
public ValidatorHostContext forRemoteReference(StructureDefinition profile, Element resource) {
|
||||
ValidatorHostContext res = new ValidatorHostContext(appContext);
|
||||
res.resource = resource;
|
||||
res.rootResource = resource;
|
||||
res.container = resource;
|
||||
res.profile = profile;
|
||||
res.checkSpecials = false;
|
||||
return res;
|
||||
}
|
||||
|
||||
public ValidatorHostContext forSlicing() {
|
||||
ValidatorHostContext res = new ValidatorHostContext(appContext);
|
||||
res.resource = resource;
|
||||
res.rootResource = resource;
|
||||
res.container = resource;
|
||||
res.profile = profile;
|
||||
res.checkSpecials = false;
|
||||
res.sliceRecords = new HashMap<String, List<ValidationMessage>>();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -26,7 +26,7 @@ import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext;
|
|||
import org.hl7.fhir.r5.utils.IResourceValidator;
|
||||
import org.hl7.fhir.r5.utils.IResourceValidator.IValidatorResourceFetcher;
|
||||
import org.hl7.fhir.r5.utils.IResourceValidator.ReferenceValidationPolicy;
|
||||
import org.hl7.fhir.r5.validation.InstanceValidator;
|
||||
import org.hl7.fhir.r5.validation.instancevalidator.InstanceValidator;
|
||||
import org.hl7.fhir.r5.validation.ValidationEngine;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
|
|
Loading…
Reference in New Issue