Merge branch 'master' of https://github.com/hapifhir/org.hl7.fhir.core into grahame_work

This commit is contained in:
Grahame Grieve 2020-02-23 07:44:17 +11:00
commit 82a4c02a8f
13 changed files with 6186 additions and 5890 deletions

View File

@ -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;

View File

@ -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;

View File

@ -1,4 +1,4 @@
package org.hl7.fhir.r5.validation;
package org.hl7.fhir.r5.validation.instancevalidator;
import org.hl7.fhir.exceptions.FHIRException;

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;