Merge pull request #243 from hapifhir/gg-work
update test case dependency
This commit is contained in:
commit
eefda87962
|
@ -773,6 +773,11 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
txCache = new TerminologyCache(lock, cachePath);
|
||||
}
|
||||
|
||||
public void clearTSCache(String url) throws Exception {
|
||||
txCache.removeCS(url);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<ConceptMap> findMapsForSource(String url) throws FHIRException {
|
||||
synchronized (lock) {
|
||||
|
|
|
@ -460,6 +460,15 @@ public class TerminologyCache {
|
|||
public static void setNoCaching(boolean noCaching) {
|
||||
TerminologyCache.noCaching = noCaching;
|
||||
}
|
||||
|
||||
public void removeCS(String url) {
|
||||
synchronized (lock) {
|
||||
String name = getNameForSystem(url);
|
||||
if (caches.containsKey(name)) {
|
||||
caches.remove(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -655,7 +655,9 @@ public class DataRenderer {
|
|||
protected void renderQuantity(XhtmlNode x, Quantity q, boolean showCodeDetails) {
|
||||
if (q.hasComparator())
|
||||
x.addText(q.getComparator().toCode());
|
||||
x.addText(q.getValue().toString());
|
||||
if (q.hasValue()) {
|
||||
x.addText(q.getValue().toString());
|
||||
}
|
||||
if (q.hasUnit())
|
||||
x.tx(" "+q.getUnit());
|
||||
else if (q.hasCode())
|
||||
|
|
|
@ -17,6 +17,7 @@ import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper;
|
|||
import org.hl7.fhir.r5.renderers.utils.DirectWrappers;
|
||||
import org.hl7.fhir.r5.renderers.utils.RenderingContext;
|
||||
import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext;
|
||||
import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceWithReference;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
||||
|
||||
|
@ -24,8 +25,8 @@ public class DiagnosticReportRenderer extends ResourceRenderer {
|
|||
|
||||
public class ObservationNode {
|
||||
private String ref;
|
||||
private ResourceWrapper obs;
|
||||
private List<ObservationNode> contained = new ArrayList<ObservationNode>();
|
||||
private ResourceWithReference obs;
|
||||
private List<ObservationNode> contained;
|
||||
}
|
||||
|
||||
|
||||
|
@ -59,7 +60,7 @@ public class DiagnosticReportRenderer extends ResourceRenderer {
|
|||
render(h2, getProperty(dr, "issued").value());
|
||||
}
|
||||
|
||||
XhtmlNode tbl = x.table( "grid");
|
||||
XhtmlNode tbl = x.table("grid");
|
||||
XhtmlNode tr = tbl.tr();
|
||||
XhtmlNode tdl = tr.td();
|
||||
XhtmlNode tdr = tr.td();
|
||||
|
@ -96,7 +97,7 @@ public class DiagnosticReportRenderer extends ResourceRenderer {
|
|||
|
||||
pw = getProperty(dr, "result");
|
||||
if (valued(pw)) {
|
||||
List<ObservationNode> observations = fetchObservations(pw.getValues());
|
||||
List<ObservationNode> observations = fetchObservations(pw.getValues(), dr);
|
||||
buildObservationsTable(x, observations);
|
||||
}
|
||||
|
||||
|
@ -149,11 +150,25 @@ public class DiagnosticReportRenderer extends ResourceRenderer {
|
|||
c.tx("to do");
|
||||
}
|
||||
|
||||
private List<ObservationNode> fetchObservations(List<BaseWrapper> list) {
|
||||
return new ArrayList<ObservationNode>();
|
||||
private List<ObservationNode> fetchObservations(List<BaseWrapper> list, ResourceWrapper rw) throws UnsupportedEncodingException, FHIRException, IOException {
|
||||
List<ObservationNode> res = new ArrayList<ObservationNode>();
|
||||
for (BaseWrapper b : list) {
|
||||
if (b.has("reference")) {
|
||||
ObservationNode obs = new ObservationNode();
|
||||
obs.ref = b.get("reference").primitiveValue();
|
||||
obs.obs = resolveReference(rw, obs.ref);
|
||||
if (obs.obs.getResource() != null) {
|
||||
PropertyWrapper t = getProperty(obs.obs.getResource(), "contained");
|
||||
if (t.hasValues()) {
|
||||
obs.contained = fetchObservations(t.getValues(), rw);
|
||||
}
|
||||
}
|
||||
res.add(obs);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
private void buildObservationsTable(XhtmlNode root, List<ObservationNode> observations) {
|
||||
XhtmlNode tbl = root.table( "none");
|
||||
for (ObservationNode o : observations) {
|
||||
|
@ -163,16 +178,21 @@ public class DiagnosticReportRenderer extends ResourceRenderer {
|
|||
|
||||
private void addObservationToTable(XhtmlNode tbl, ObservationNode o, int i) {
|
||||
XhtmlNode tr = tbl.tr();
|
||||
if (o.obs == null) {
|
||||
if (o.obs.getReference() == null) {
|
||||
XhtmlNode td = tr.td().colspan("6");
|
||||
td.i().tx("This Observation could not be resolved");
|
||||
} else {
|
||||
addObservationToTable(tr, o.obs, i);
|
||||
// todo: contained observations
|
||||
}
|
||||
for (ObservationNode c : o.contained) {
|
||||
addObservationToTable(tbl, c, i+1);
|
||||
}
|
||||
if (o.obs.getResource() != null) {
|
||||
addObservationToTable(tr, o.obs.getResource(), i);
|
||||
} else {
|
||||
tr.td().tx("Unable to resolve Observation: "+o.obs.getReference());
|
||||
}
|
||||
if (o.contained != null) {
|
||||
for (ObservationNode c : o.contained) {
|
||||
addObservationToTable(tbl, c, i+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addObservationToTable(XhtmlNode tr, ResourceWrapper obs, int i) {
|
||||
|
@ -180,7 +200,7 @@ public class DiagnosticReportRenderer extends ResourceRenderer {
|
|||
|
||||
// code (+bodysite)
|
||||
XhtmlNode td = tr.td();
|
||||
PropertyWrapper pw = getProperty(obs, "result");
|
||||
PropertyWrapper pw = getProperty(obs, "code");
|
||||
if (valued(pw)) {
|
||||
render(td, pw.value());
|
||||
}
|
||||
|
@ -195,12 +215,7 @@ public class DiagnosticReportRenderer extends ResourceRenderer {
|
|||
td = tr.td();
|
||||
pw = getProperty(obs, "value[x]");
|
||||
if (valued(pw)) {
|
||||
if (pw.getTypeCode().equals("CodeableConcept"))
|
||||
render(td, pw.value());
|
||||
else if (pw.getTypeCode().equals("string"))
|
||||
render(td, pw.value());
|
||||
else
|
||||
td.addText(pw.getTypeCode()+" not rendered yet");
|
||||
render(td, pw.value());
|
||||
}
|
||||
|
||||
// units
|
||||
|
|
|
@ -53,6 +53,7 @@ public class ListRenderer extends ResourceRenderer {
|
|||
td.tx("Code: "+displayBase(list.get("code")));
|
||||
}
|
||||
tr = t.tr();
|
||||
td = tr.td();
|
||||
if (list.has("subject")) {
|
||||
td.tx("Subject: ");
|
||||
shortForRef(td, list.get("subject"));
|
||||
|
@ -80,27 +81,27 @@ public class ListRenderer extends ResourceRenderer {
|
|||
}
|
||||
t = x.table("grid");
|
||||
tr = t.tr().style("backgound-color: #eeeeee");
|
||||
td.b().tx("Items");
|
||||
tr.td().b().tx("Items");
|
||||
if (date) {
|
||||
td.tx("Date");
|
||||
tr.td().tx("Date");
|
||||
}
|
||||
if (flag) {
|
||||
td.tx("Flag");
|
||||
tr.td().tx("Flag");
|
||||
}
|
||||
if (deleted) {
|
||||
td.tx("Deleted");
|
||||
tr.td().tx("Deleted");
|
||||
}
|
||||
for (BaseWrapper e : list.children("entry")) {
|
||||
tr = t.tr();
|
||||
shortForRef(td, e.get("item"));
|
||||
shortForRef(tr.td(), e.get("item"));
|
||||
if (date) {
|
||||
td.tx(e.has("date") ? e.get("date").dateTimeValue().toHumanDisplay() : "");
|
||||
tr.td().tx(e.has("date") ? e.get("date").dateTimeValue().toHumanDisplay() : "");
|
||||
}
|
||||
if (flag) {
|
||||
td.tx(e.has("flag") ? displayBase(e.get("flag")) : "");
|
||||
tr.td().tx(e.has("flag") ? displayBase(e.get("flag")) : "");
|
||||
}
|
||||
if (deleted) {
|
||||
td.tx(e.has("deleted") ? e.get("deleted").primitiveValue() : "");
|
||||
tr.td().tx(e.has("deleted") ? e.get("deleted").primitiveValue() : "");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -211,8 +212,10 @@ public class ListRenderer extends ResourceRenderer {
|
|||
disp = url;
|
||||
}
|
||||
x.tx(disp);
|
||||
} else {
|
||||
} else if (r.getResource() != null) {
|
||||
RendererFactory.factory(r.getResource().getName(), context).renderReference(r.getResource(), x, (Reference) ref);
|
||||
} else {
|
||||
RendererFactory.factory(url, context).renderReference(r.getResource(), x, (Reference) ref);
|
||||
}
|
||||
} else if (disp != null) {
|
||||
x.tx(disp);
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.hl7.fhir.r5.model.Base64BinaryType;
|
|||
import org.hl7.fhir.r5.model.BooleanType;
|
||||
import org.hl7.fhir.r5.model.CodeType;
|
||||
import org.hl7.fhir.r5.model.CodeableConcept;
|
||||
import org.hl7.fhir.r5.model.CodeableReference;
|
||||
import org.hl7.fhir.r5.model.Coding;
|
||||
import org.hl7.fhir.r5.model.ContactDetail;
|
||||
import org.hl7.fhir.r5.model.ContactPoint;
|
||||
|
@ -227,7 +228,7 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
|
|||
first = false;
|
||||
else if (last)
|
||||
x.tx(", ");
|
||||
last = displayLeaf(res, v, child, x, p.getName(), showCodeDetails) || last;
|
||||
last = displayLeaf(res, v, child, x, p.getName(), showCodeDetails, false) || last;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -353,6 +354,10 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
|
|||
}
|
||||
|
||||
private boolean displayLeaf(ResourceWrapper res, BaseWrapper ew, ElementDefinition defn, XhtmlNode x, String name, boolean showCodeDetails) throws FHIRException, UnsupportedEncodingException, IOException {
|
||||
return displayLeaf(res, ew, defn, x, name, showCodeDetails, true);
|
||||
}
|
||||
|
||||
private boolean displayLeaf(ResourceWrapper res, BaseWrapper ew, ElementDefinition defn, XhtmlNode x, String name, boolean showCodeDetails, boolean allowLinks) throws FHIRException, UnsupportedEncodingException, IOException {
|
||||
if (ew == null)
|
||||
return false;
|
||||
Base e = ew.getBase();
|
||||
|
@ -399,6 +404,14 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
|
|||
x.addText(name);
|
||||
return true;
|
||||
}
|
||||
} else if (e instanceof CodeableReference) {
|
||||
if (((CodeableReference) e).hasReference()) {
|
||||
Reference r = ((CodeableReference) e).getReference();
|
||||
renderReference(res, x, r, allowLinks);
|
||||
} else {
|
||||
renderCodeableConcept(x, ((CodeableReference) e).getConcept(), showCodeDetails);
|
||||
}
|
||||
return true;
|
||||
} else if (e instanceof CodeableConcept) {
|
||||
renderCodeableConcept(x, (CodeableConcept) e, showCodeDetails);
|
||||
return true;
|
||||
|
|
|
@ -118,9 +118,13 @@ public abstract class ResourceRenderer extends DataRenderer {
|
|||
}
|
||||
|
||||
public void renderReference(ResourceWrapper rw, XhtmlNode x, Reference r) throws UnsupportedEncodingException, IOException {
|
||||
XhtmlNode c = x;
|
||||
renderReference(rw, x, r, true);
|
||||
}
|
||||
|
||||
public void renderReference(ResourceWrapper rw, XhtmlNode x, Reference r, boolean allowLinks) throws UnsupportedEncodingException, IOException {
|
||||
XhtmlNode c = null;
|
||||
ResourceWithReference tr = null;
|
||||
if (r.hasReferenceElement()) {
|
||||
if (r.hasReferenceElement() && allowLinks) {
|
||||
tr = resolveReference(rw, r.getReference());
|
||||
|
||||
if (!r.getReference().startsWith("#")) {
|
||||
|
@ -129,6 +133,8 @@ public abstract class ResourceRenderer extends DataRenderer {
|
|||
else
|
||||
c = x.ah(r.getReference());
|
||||
}
|
||||
} else {
|
||||
c = x.span(null, null);
|
||||
}
|
||||
// what to display: if text is provided, then that. if the reference was resolved, then show the generated narrative
|
||||
if (r.hasDisplayElement()) {
|
||||
|
@ -178,7 +184,7 @@ public abstract class ResourceRenderer extends DataRenderer {
|
|||
protected ResourceWithReference resolveReference(ResourceWrapper res, String url) {
|
||||
if (url == null)
|
||||
return null;
|
||||
if (url.startsWith("#")) {
|
||||
if (url.startsWith("#") && res != null) {
|
||||
for (ResourceWrapper r : res.getContained()) {
|
||||
if (r.getId().equals(url.substring(1)))
|
||||
return new ResourceWithReference(null, r);
|
||||
|
@ -249,8 +255,12 @@ public abstract class ResourceRenderer extends DataRenderer {
|
|||
protected ResourceWrapper fetchResource(BaseWrapper subject) throws UnsupportedEncodingException, FHIRException, IOException {
|
||||
if (context.getResolver() == null)
|
||||
return null;
|
||||
|
||||
String url = subject.getChildByName("reference").value().getBase().primitiveValue();
|
||||
|
||||
PropertyWrapper ref = subject.getChildByName("reference");
|
||||
if (ref == null || !ref.hasValues()) {
|
||||
return null;
|
||||
}
|
||||
String url = ref.value().getBase().primitiveValue();
|
||||
ResourceWithReference rr = context.getResolver().resolve(context, url);
|
||||
return rr == null ? null : rr.getResource();
|
||||
}
|
||||
|
|
|
@ -64,6 +64,10 @@ public class DOMWrappers {
|
|||
public List<PropertyWrapper> children() {
|
||||
if (list == null) {
|
||||
children = context.getProfileUtilities().getChildList(structure, definition);
|
||||
if (children.isEmpty() && type != null) {
|
||||
StructureDefinition sdt = context.getWorker().fetchTypeDefinition(type);
|
||||
children = context.getProfileUtilities().getChildList(sdt, sdt.getSnapshot().getElementFirstRep());
|
||||
}
|
||||
list = new ArrayList<PropertyWrapper>();
|
||||
for (ElementDefinition child : children) {
|
||||
List<Element> elements = new ArrayList<Element>();
|
||||
|
@ -140,8 +144,17 @@ public class DOMWrappers {
|
|||
|
||||
@Override
|
||||
public String getTypeCode() {
|
||||
if (definition == null || definition.getType().size() != 1)
|
||||
throw new Error("not handled");
|
||||
if (definition == null || definition.getType().size() != 1) {
|
||||
if (values.size() != 1) {
|
||||
throw new Error("not handled");
|
||||
}
|
||||
String tn = values.get(0).getLocalName().substring(tail(definition.getPath()).replace("[x]", "").length());
|
||||
if (isPrimitive(Utilities.uncapitalize(tn))) {
|
||||
return Utilities.uncapitalize(tn);
|
||||
} else {
|
||||
return tn;
|
||||
}
|
||||
}
|
||||
return definition.getType().get(0).getWorkingCode();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,276 @@
|
|||
package org.hl7.fhir.r5.utils;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.xmlbeans.xml.stream.ReferenceResolver;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r5.context.IWorkerContext;
|
||||
import org.hl7.fhir.r5.model.Base;
|
||||
import org.hl7.fhir.r5.model.Bundle;
|
||||
import org.hl7.fhir.r5.model.Expression;
|
||||
import org.hl7.fhir.r5.model.ExpressionNode;
|
||||
import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent;
|
||||
import org.hl7.fhir.r5.model.GraphDefinition;
|
||||
import org.hl7.fhir.r5.model.GraphDefinition.GraphDefinitionLinkComponent;
|
||||
import org.hl7.fhir.r5.model.GraphDefinition.GraphDefinitionLinkTargetComponent;
|
||||
import org.hl7.fhir.r5.model.Reference;
|
||||
import org.hl7.fhir.r5.model.Resource;
|
||||
import org.hl7.fhir.r5.model.StringType;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.graphql.Argument;
|
||||
import org.hl7.fhir.utilities.graphql.EGraphEngine;
|
||||
import org.hl7.fhir.utilities.graphql.EGraphQLException;
|
||||
import org.hl7.fhir.utilities.graphql.GraphQLResponse;
|
||||
import org.hl7.fhir.utilities.graphql.IGraphQLStorageServices;
|
||||
import org.hl7.fhir.utilities.graphql.IGraphQLStorageServices.ReferenceResolution;
|
||||
import org.hl7.fhir.utilities.graphql.StringValue;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
public class GraphDefinitionEngine {
|
||||
|
||||
|
||||
private static final String TAG_NAME = "Compiled.expression";
|
||||
|
||||
private IGraphQLStorageServices services;
|
||||
private IWorkerContext context;
|
||||
/**
|
||||
* for the host to pass context into and get back on the reference resolution interface
|
||||
*/
|
||||
private Object appInfo;
|
||||
|
||||
/**
|
||||
* the focus resource - if (there instanceof one. if (there isn"t,) there instanceof no focus
|
||||
*/
|
||||
private Resource start;
|
||||
|
||||
/**
|
||||
* The package that describes the graphQL to be executed, operation name, and variables
|
||||
*/
|
||||
private GraphDefinition graphDefinition;
|
||||
|
||||
/**
|
||||
* If the graph definition is being run to validate a grph
|
||||
*/
|
||||
private boolean validating;
|
||||
|
||||
/**
|
||||
* where the output from executing the query instanceof going to go
|
||||
*/
|
||||
private Bundle bundle;
|
||||
|
||||
private String baseURL;
|
||||
private FHIRPathEngine engine;
|
||||
|
||||
public GraphDefinitionEngine(IGraphQLStorageServices services, IWorkerContext context) {
|
||||
super();
|
||||
this.services = services;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public Object getAppInfo() {
|
||||
return appInfo;
|
||||
}
|
||||
|
||||
public void setAppInfo(Object appInfo) {
|
||||
this.appInfo = appInfo;
|
||||
}
|
||||
|
||||
public Resource getFocus() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public void setFocus(Resource focus) {
|
||||
this.start = focus;
|
||||
}
|
||||
|
||||
public GraphDefinition getGraphDefinition() {
|
||||
return graphDefinition;
|
||||
}
|
||||
|
||||
public void setGraphDefinition(GraphDefinition graphDefinition) {
|
||||
this.graphDefinition = graphDefinition;
|
||||
}
|
||||
|
||||
public Bundle getOutput() {
|
||||
return bundle;
|
||||
}
|
||||
|
||||
public void setOutput(Bundle bundle) {
|
||||
this.bundle = bundle;
|
||||
}
|
||||
|
||||
public IGraphQLStorageServices getServices() {
|
||||
return services;
|
||||
}
|
||||
|
||||
public IWorkerContext getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
public String getBaseURL() {
|
||||
return baseURL;
|
||||
}
|
||||
|
||||
public void setBaseURL(String baseURL) {
|
||||
this.baseURL = baseURL;
|
||||
}
|
||||
|
||||
public boolean isValidating() {
|
||||
return validating;
|
||||
}
|
||||
|
||||
public void setValidating(boolean validating) {
|
||||
this.validating = validating;
|
||||
}
|
||||
|
||||
public void execute() throws EGraphEngine, EGraphQLException, FHIRException {
|
||||
assert services != null;
|
||||
assert start != null;
|
||||
assert bundle != null;
|
||||
assert baseURL != null;
|
||||
assert graphDefinition != null;
|
||||
graphDefinition.checkNoModifiers("definition", "Building graph from GraphDefinition");
|
||||
|
||||
check(!start.fhirType().equals(graphDefinition.getStart()), "The Graph definition requires that the start (focus reosource) is "+graphDefinition.getStart()+", but instead found "+start.fhirType());
|
||||
|
||||
if (!isInBundle(start)) {
|
||||
addToBundle(start);
|
||||
}
|
||||
for (GraphDefinitionLinkComponent l : graphDefinition.getLink()) {
|
||||
processLink(start.fhirType(), start, l, 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void check(boolean b, String msg) {
|
||||
if (!b) {
|
||||
throw new FHIRException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInBundle(Resource resource) {
|
||||
for (BundleEntryComponent be : bundle.getEntry()) {
|
||||
if (be.hasResource() && be.getResource().fhirType().equals(resource.fhirType()) && be.getResource().getId().equals(resource.getId())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void addToBundle(Resource resource) {
|
||||
BundleEntryComponent be = bundle.addEntry();
|
||||
be.setFullUrl(Utilities.pathURL(baseURL, resource.fhirType(), resource.getId()));
|
||||
be.setResource(resource);
|
||||
}
|
||||
|
||||
private void processLink(String focusPath, Resource focus, GraphDefinitionLinkComponent link, int depth) {
|
||||
if (link.hasPath()) {
|
||||
processLinkPath(focusPath, focus, link, depth);
|
||||
} else {
|
||||
processLinkTarget(focusPath, focus, link, depth);
|
||||
}
|
||||
}
|
||||
|
||||
private void processLinkPath(String focusPath, Resource focus, GraphDefinitionLinkComponent link, int depth) {
|
||||
String path = focusPath+" -> "+link.getPath();
|
||||
check(link.hasPath(), "Path is needed at "+path);
|
||||
check(!link.hasSliceName(), "SliceName is not yet supported at "+path);
|
||||
|
||||
ExpressionNode node;
|
||||
if (link.getPathElement().hasUserData(TAG_NAME)) {
|
||||
node = (ExpressionNode) link.getPathElement().getUserData(TAG_NAME);
|
||||
} else {
|
||||
node = engine.parse(link.getPath());
|
||||
link.getPathElement().setUserData(TAG_NAME, node);
|
||||
}
|
||||
List<Base> matches = engine.evaluate(null, focus, focus, focus, node);
|
||||
check(!validating || matches.size() >= (link.hasMin() ? link.getMin() : 0), "Link at path "+path+" requires at least "+link.getMin()+" matches, but only found "+matches.size());
|
||||
check(!validating || matches.size() <= (link.hasMax() ? Integer.parseInt(link.getMax()) : Integer.MAX_VALUE), "Link at path "+path+" requires at most "+link.getMax()+" matches, but found "+matches.size());
|
||||
for (Base sel : matches) {
|
||||
check(sel.fhirType().equals("Reference"), "Selected node from an expression must be a Reference"); // todo: should a URL be ok?
|
||||
ReferenceResolution res = services.lookup(appInfo, focus, (Reference) sel);
|
||||
if (res != null) {
|
||||
check(res.getTargetContext() != focus, "how to handle contained resources is not yet resolved"); // todo
|
||||
for (GraphDefinitionLinkTargetComponent tl : link.getTarget()) {
|
||||
if (tl.getType().equals(res.getTarget().fhirType())) {
|
||||
Resource r = (Resource) res.getTarget();
|
||||
if (!isInBundle(r)) {
|
||||
addToBundle(r);
|
||||
for (GraphDefinitionLinkComponent l : graphDefinition.getLink()) {
|
||||
processLink(focus.fhirType(), r, l, depth+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processLinkTarget(String focusPath, Resource focus, GraphDefinitionLinkComponent link, int depth) {
|
||||
check(link.getTarget().size() == 1, "If there is no path, there must be one and only one target at "+focusPath);
|
||||
check(link.getTarget().get(0).hasType(), "If there is no path, there must be type on the target at "+focusPath);
|
||||
check(link.getTarget().get(0).getParams().contains("{ref}"), "If there is no path, the target must have parameters that include a parameter using {ref} at "+focusPath);
|
||||
String path = focusPath+" -> "+link.getTarget().get(0).getType()+"?"+link.getTarget().get(0).getParams();
|
||||
|
||||
List<IBaseResource> list = new ArrayList<>();
|
||||
List<Argument> params = new ArrayList<>();
|
||||
parseParams(params, link.getTarget().get(0).getParams(), focus);
|
||||
services.listResources(appInfo, link.getTarget().get(0).getType(), params, list);
|
||||
check(!validating || (list.size() >= (link.hasMin() ? link.getMin() : 0)), "Link at path "+path+" requires at least "+link.getMin()+" matches, but only found "+list.size());
|
||||
check(!validating || (list.size() <= (link.hasMax() && !link.getMax().equals("*") ? Integer.parseInt(link.getMax()) : Integer.MAX_VALUE)), "Link at path "+path+" requires at most "+link.getMax()+" matches, but found "+list.size());
|
||||
for (IBaseResource res : list) {
|
||||
Resource r = (Resource) res;
|
||||
if (!isInBundle(r)) {
|
||||
addToBundle(r);
|
||||
// Grahame Grieve 17-06-2020: this seems wrong to me - why restart?
|
||||
for (GraphDefinitionLinkComponent l : graphDefinition.getLink()) {
|
||||
processLink(start.fhirType(), start, l, depth+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void parseParams(List<Argument> params, String value, Resource res) {
|
||||
boolean refed = false;
|
||||
Map<String, List<String>> p = splitQuery(value);
|
||||
for (String n : p.keySet()) {
|
||||
for (String v : p.get(n)) {
|
||||
if (v.equals("{ref}")) {
|
||||
refed = true;
|
||||
v = res.fhirType()+'/'+res.getId();
|
||||
}
|
||||
params.add(new Argument(n, new StringValue(v)));
|
||||
}
|
||||
}
|
||||
check(refed, "no use of {ref} found");
|
||||
}
|
||||
|
||||
public Map<String, List<String>> splitQuery(String string) {
|
||||
final Map<String, List<String>> query_pairs = new LinkedHashMap<String, List<String>>();
|
||||
final String[] pairs = string.split("&");
|
||||
for (String pair : pairs) {
|
||||
final int idx = pair.indexOf("=");
|
||||
final String key = idx > 0 ? decode(pair.substring(0, idx), "UTF-8") : pair;
|
||||
if (!query_pairs.containsKey(key)) {
|
||||
query_pairs.put(key, new LinkedList<String>());
|
||||
}
|
||||
final String value = idx > 0 && pair.length() > idx + 1 ? decode(pair.substring(idx + 1), "UTF-8") : null;
|
||||
query_pairs.get(key).add(value);
|
||||
}
|
||||
return query_pairs;
|
||||
}
|
||||
|
||||
private String decode(String s, String enc) {
|
||||
try {
|
||||
return URLDecoder.decode(s, enc);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package org.hl7.fhir.r5.utils;
|
||||
|
||||
/*
|
||||
Copyright (c) 2011+, HL7, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of HL7 nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r5.model.Bundle;
|
||||
import org.hl7.fhir.r5.model.GraphDefinition;
|
||||
import org.hl7.fhir.utilities.graphql.EGraphEngine;
|
||||
import org.hl7.fhir.utilities.graphql.EGraphQLException;
|
||||
import org.hl7.fhir.utilities.graphql.IGraphQLStorageServices;
|
||||
|
||||
public interface IGraphDefinitionEngine {
|
||||
|
||||
void execute() throws EGraphEngine, EGraphQLException, FHIRException;
|
||||
|
||||
Bundle getOutput();
|
||||
|
||||
void setAppInfo(Object appInfo);
|
||||
|
||||
void setFocus(IBaseResource focus);
|
||||
|
||||
void setGraphDefinition(GraphDefinition graphDefinition);
|
||||
|
||||
void setServices(IGraphQLStorageServices services);
|
||||
}
|
|
@ -96,6 +96,7 @@ public class ClientUtils {
|
|||
|
||||
public static final String DEFAULT_CHARSET = "UTF-8";
|
||||
public static final String HEADER_LOCATION = "location";
|
||||
private static boolean debugging = false;
|
||||
|
||||
private HttpHost proxy;
|
||||
private int timeout = 5000;
|
||||
|
@ -323,6 +324,9 @@ public class ClientUtils {
|
|||
}
|
||||
response = httpclient.execute(request);
|
||||
} catch(IOException ioe) {
|
||||
if (ClientUtils.debugging ) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
throw new EFhirClientException("Error sending Http Request: "+ioe.getMessage(), ioe);
|
||||
}
|
||||
return response;
|
||||
|
|
|
@ -323,13 +323,6 @@ public class BaseValidator {
|
|||
* @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation)
|
||||
*/
|
||||
|
||||
//todo: delete this when finished i18n
|
||||
protected boolean rule(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg) {
|
||||
if (!thePass) {
|
||||
addValidationMessage(errors, type, -1, -1, path, msg, IssueSeverity.ERROR, null);
|
||||
}
|
||||
return thePass;
|
||||
}
|
||||
|
||||
protected boolean rule(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String theMessage, Object... theMessageArguments) {
|
||||
if (!thePass) {
|
||||
|
|
|
@ -2,7 +2,6 @@ package org.hl7.fhir.validation.cli.model;
|
|||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import org.hl7.fhir.validation.Validator;
|
||||
import org.hl7.fhir.validation.cli.utils.SnomedVersion;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
|
@ -47,7 +46,7 @@ public class CliContext {
|
|||
@JsonProperty("fhirpath")
|
||||
private String fhirpath = null;
|
||||
@JsonProperty("snomedCT")
|
||||
private String snomedCT = SnomedVersion.INTL.getCode();
|
||||
private String snomedCT = "900000000000207008";
|
||||
@JsonProperty("targetVer")
|
||||
private String targetVer = null;
|
||||
|
||||
|
@ -339,12 +338,18 @@ public class CliContext {
|
|||
return this;
|
||||
}
|
||||
|
||||
public SnomedVersion getSnomedCT() {
|
||||
return SnomedVersion.getFromCode(snomedCT);
|
||||
}
|
||||
|
||||
@JsonProperty("snomedCT")
|
||||
public String getSnomedCTCode() {
|
||||
if ("intl".equals(snomedCT)) return "900000000000207008";
|
||||
if ("us".equals(snomedCT)) return "731000124108";
|
||||
if ("uk".equals(snomedCT)) return "999000041000000102";
|
||||
if ("au".equals(snomedCT)) return "32506021000036107";
|
||||
if ("ca".equals(snomedCT)) return "20611000087101";
|
||||
if ("nl".equals(snomedCT)) return "11000146104";
|
||||
if ("se".equals(snomedCT)) return "45991000052106";
|
||||
if ("es".equals(snomedCT)) return "449081005";
|
||||
if ("dk".equals(snomedCT)) return "554471000005108";
|
||||
return snomedCT;
|
||||
}
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ public class Params {
|
|||
throw new Error("Specified -profile without indicating profile source");
|
||||
} else {
|
||||
p = args[++i];
|
||||
cliContext.addProfile(args[i++]);
|
||||
cliContext.addProfile(p);
|
||||
}
|
||||
if (p != null && i + 1 < args.length && args[i + 1].equals("@")) {
|
||||
i++;
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
package org.hl7.fhir.validation.cli.utils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public enum SnomedVersion {
|
||||
INTL("intl", "900000000000207008"),
|
||||
US("us", "731000124108"),
|
||||
UK("uk", "999000041000000102"),
|
||||
AU("au", "32506021000036107"),
|
||||
CA("ca", "20611000087101"),
|
||||
NL("nl", "11000146104"),
|
||||
SE("se", "45991000052106"),
|
||||
ES("es", "449081005"),
|
||||
DK("dk", "554471000005108");
|
||||
|
||||
private static final String DEFAULT_CODE = "900000000000207008";
|
||||
|
||||
private final String lang;
|
||||
private final String code;
|
||||
|
||||
SnomedVersion(String lang, String code) {
|
||||
this.lang = lang;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getLang() {
|
||||
return lang;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public static SnomedVersion getFromCode(String code) {
|
||||
return lookup.get(code);
|
||||
}
|
||||
|
||||
private static final Map<String, SnomedVersion> lookup = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (SnomedVersion s : SnomedVersion.values()) {
|
||||
lookup.put(s.getCode(), s);
|
||||
}
|
||||
}
|
||||
}
|
2
pom.xml
2
pom.xml
|
@ -17,7 +17,7 @@
|
|||
|
||||
<properties>
|
||||
<hapi_fhir_version>5.0.0</hapi_fhir_version>
|
||||
<validator_test_case_version>1.1.19</validator_test_case_version>
|
||||
<validator_test_case_version>1.1.20</validator_test_case_version>
|
||||
<junit_jupiter_version>5.6.2</junit_jupiter_version>
|
||||
<maven_surefire_version>3.0.0-M4</maven_surefire_version>
|
||||
<jacoco_version>0.8.5</jacoco_version>
|
||||
|
|
Loading…
Reference in New Issue