Merge branch 'hapifhir:master' into master
This commit is contained in:
commit
34d8dfa24d
|
@ -0,0 +1,28 @@
|
|||
name: BIDI CHECK
|
||||
|
||||
# Controls when the workflow will run
|
||||
on:
|
||||
# Triggers the workflow on push or pull request events but only for the main branch
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
bidi_checker_job:
|
||||
runs-on: ubuntu-latest
|
||||
name: Check for bidi unicode characters in repo
|
||||
steps:
|
||||
# Checkout the repo code. IMPORTANT, this step is needed to populate the directory defined by GITHUB_WORKSPACE
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v1
|
||||
id: checkout
|
||||
# Run the check for bidi characters.
|
||||
- name: Check for bidi characters
|
||||
id: bidi_check
|
||||
uses: HL7/bidi-checker-action@v1.5
|
||||
- name: Get the output time
|
||||
run: echo "The time was ${{ steps.bidi_check.outputs.time }}"
|
|
@ -4,7 +4,7 @@
|
|||
| :---: |
|
||||
| [![Build Status][Badge-BuildPipeline]][Link-BuildPipeline] |
|
||||
|
||||
This is the core object handling code, with utilities (including validator), for the FHIR specification.
|
||||
This is the java core object handling code, with utilities (including validator), for the FHIR specification.
|
||||
included in this repo:
|
||||
|
||||
* org.fhir.fhir.utilities: Shared code used by all the other projects - including the internationalization code
|
||||
|
@ -17,6 +17,11 @@ included in this repo:
|
|||
* org.fhir.fhir.validation: The FHIR Java validator (note: based on R5 internally, but validates all the above versions)
|
||||
* org.fhir.fhir.validation.cli: Holder project for releasing the FHIR validator as as single fat jar (will be removed in the future)
|
||||
|
||||
This code is used in all HAPI servers and clients, and also is the HL7 maintained
|
||||
FHIR Validator. In addition, this is the core code for the HL7 maintained IG publisher
|
||||
and FHIR main build publisher. As such, this code is considered an authoritatively
|
||||
correct implementation of the core FHIR specification that it implements.
|
||||
|
||||
### CI/CD
|
||||
|
||||
All integration and delivery done on Azure pipelines. Azure project can be viewed [here][Link-AzureProject].
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
Code changes:
|
||||
* remove erroneous logging to c:\temp
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>5.5.12-SNAPSHOT</version>
|
||||
<version>5.6.16-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
@ -89,7 +89,7 @@
|
|||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.16</version>
|
||||
<version>${lombok_version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
|
|
@ -613,10 +613,10 @@ public class ElementDefinition30_40 {
|
|||
Type t = ConversionContext30_40.INSTANCE.getVersionConvertor_30_40().convertType(src.getValueSet());
|
||||
if (t instanceof org.hl7.fhir.r4.model.Reference) {
|
||||
tgt.setValueSet(((org.hl7.fhir.r4.model.Reference) t).getReference());
|
||||
tgt.getValueSetElement().addExtension(VersionConvertor_30_40.EXT_SRC_TYPE, new UriType("Reference"));
|
||||
tgt.getValueSetElement().addExtension(VersionConvertor_30_40.EXT_SRC_TYPE, new org.hl7.fhir.r4.model.UrlType("Reference"));
|
||||
} else {
|
||||
tgt.setValueSet(t.primitiveValue());
|
||||
tgt.getValueSetElement().addExtension(VersionConvertor_30_40.EXT_SRC_TYPE, new UriType("uri"));
|
||||
tgt.getValueSetElement().addExtension(VersionConvertor_30_40.EXT_SRC_TYPE, new org.hl7.fhir.r4.model.UrlType("uri"));
|
||||
}
|
||||
tgt.setValueSet(VersionConvertorConstants.refToVS(tgt.getValueSet()));
|
||||
}
|
||||
|
|
|
@ -625,10 +625,10 @@ public class ElementDefinition30_50 {
|
|||
DataType t = ConversionContext30_50.INSTANCE.getVersionConvertor_30_50().convertType(src.getValueSet());
|
||||
if (t instanceof org.hl7.fhir.r5.model.Reference) {
|
||||
tgt.setValueSet(((org.hl7.fhir.r5.model.Reference) t).getReference());
|
||||
tgt.getValueSetElement().addExtension(VersionConvertor_30_50.EXT_SRC_TYPE, new UriType("Reference"));
|
||||
tgt.getValueSetElement().addExtension(VersionConvertor_30_50.EXT_SRC_TYPE, new org.hl7.fhir.r5.model.UrlType("Reference"));
|
||||
} else {
|
||||
tgt.setValueSet(t.primitiveValue());
|
||||
tgt.getValueSetElement().addExtension(VersionConvertor_30_50.EXT_SRC_TYPE, new UriType("uri"));
|
||||
tgt.getValueSetElement().addExtension(VersionConvertor_30_50.EXT_SRC_TYPE, new org.hl7.fhir.r5.model.UrlType("uri"));
|
||||
}
|
||||
tgt.setValueSet(VersionConvertorConstants.refToVS(tgt.getValueSet()));
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ public abstract class BaseLoaderR5 implements IContextResourceLoader {
|
|||
if (VersionUtilities.isR5Ver(npm.fhirVersion())) {
|
||||
return new R5ToR5Loader(types, lkp.forNewPackage(npm));
|
||||
} else if (VersionUtilities.isR4Ver(npm.fhirVersion())) {
|
||||
return new R4ToR5Loader(types, lkp.forNewPackage(npm));
|
||||
return new R4ToR5Loader(types, lkp.forNewPackage(npm), npm.version());
|
||||
} else if (VersionUtilities.isR3Ver(npm.fhirVersion())) {
|
||||
return new R3ToR5Loader(types, lkp.forNewPackage(npm));
|
||||
} else if (VersionUtilities.isR2Ver(npm.fhirVersion())) {
|
||||
|
|
|
@ -36,12 +36,14 @@ import org.hl7.fhir.exceptions.FHIRException;
|
|||
import org.hl7.fhir.r4.formats.JsonParser;
|
||||
import org.hl7.fhir.r4.formats.XmlParser;
|
||||
import org.hl7.fhir.r4.model.Resource;
|
||||
import org.hl7.fhir.r5.conformance.StructureDefinitionHacker;
|
||||
import org.hl7.fhir.r5.context.IWorkerContext.IContextResourceLoader;
|
||||
import org.hl7.fhir.r5.model.*;
|
||||
import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent;
|
||||
import org.hl7.fhir.r5.model.Bundle.BundleType;
|
||||
import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
|
||||
import org.hl7.fhir.utilities.VersionUtilities;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -52,9 +54,11 @@ import java.util.UUID;
|
|||
public class R4ToR5Loader extends BaseLoaderR5 implements IContextResourceLoader {
|
||||
|
||||
private final BaseAdvisor_40_50 advisor = new BaseAdvisor_40_50();
|
||||
private String version;
|
||||
|
||||
public R4ToR5Loader(String[] types, ILoaderKnowledgeProviderR5 lkp) {
|
||||
public R4ToR5Loader(String[] types, ILoaderKnowledgeProviderR5 lkp, String version) { // might be 4B
|
||||
super(types, lkp);
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -123,6 +127,9 @@ public class R4ToR5Loader extends BaseLoaderR5 implements IContextResourceLoader
|
|||
if (killPrimitives) {
|
||||
throw new FHIRException("Cannot kill primitives when using deferred loading");
|
||||
}
|
||||
if (r5 instanceof StructureDefinition && VersionUtilities.isR4BVer(version)) {
|
||||
r5 = new StructureDefinitionHacker(version).fixSD((StructureDefinition) r5);
|
||||
}
|
||||
if (patchUrls) {
|
||||
if (r5 instanceof StructureDefinition) {
|
||||
StructureDefinition sd = (StructureDefinition) r5;
|
||||
|
|
|
@ -80,7 +80,7 @@ public class DicomPackageBuilder {
|
|||
vs.setId(vs.getId().substring(0, 64));
|
||||
}
|
||||
if (ids.contains(vs.getId())) {
|
||||
throw new Error("Duplicate Id once Ids cut off at 64 char: "+vs.getId());
|
||||
throw new Error("Duplicate Id (note Ids cut off at 64 char): "+vs.getId());
|
||||
}
|
||||
ids.add(vs.getId());
|
||||
gen.addFile(Category.RESOURCE, "ValueSet-"+vs.getId()+".json", new JsonParser().setOutputStyle(OutputStyle.NORMAL).composeBytes(vs));
|
||||
|
@ -113,7 +113,7 @@ public class DicomPackageBuilder {
|
|||
private JsonObject buildPackage() {
|
||||
JsonObject npm = new JsonObject();
|
||||
npm.addProperty("tools-version", 3);
|
||||
npm.addProperty("type", "fhir.ig");
|
||||
npm.addProperty("type", "Conformance");
|
||||
npm.addProperty("license", "free");
|
||||
npm.addProperty("author", "FHIR Project for DICOM");
|
||||
npm.addProperty("name", "fhir.dicom");
|
||||
|
|
|
@ -0,0 +1,387 @@
|
|||
package org.hl7.fhir.convertors.misc;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.naming.ldap.StartTlsRequest;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.json.JsonTrackingParser;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
public class XVerPackegeFixer {
|
||||
|
||||
private static final String R5_FOLDER = "C:\\work\\org.hl7.fhir\\packages\\hl7.fhir.rX\\hl7.fhir.r5.core\\package";
|
||||
private static final String R4_FOLDER = "C:\\work\\org.hl7.fhir\\packages\\hl7.fhir.rX\\hl7.fhir.r4.core\\package";
|
||||
private static final String R3_FOLDER = "C:\\work\\org.hl7.fhir\\packages\\hl7.fhir.rX\\hl7.fhir.r3.core\\package";
|
||||
private static final String R2B_FOLDER = "C:\\work\\org.hl7.fhir\\packages\\hl7.fhir.rX\\hl7.fhir.r2b.core\\package";
|
||||
private static final String R2_FOLDER = "C:\\work\\org.hl7.fhir\\packages\\hl7.fhir.rX\\hl7.fhir.r2.core\\package";
|
||||
private static int mod;
|
||||
|
||||
private static Map<String, org.hl7.fhir.r5.model.StructureDefinition> map5 = new HashMap<>();
|
||||
private static Map<String, org.hl7.fhir.r4.model.StructureDefinition> map4 = new HashMap<>();
|
||||
private static Map<String, org.hl7.fhir.dstu3.model.StructureDefinition> map3 = new HashMap<>();
|
||||
private static Map<String, org.hl7.fhir.dstu2.model.StructureDefinition> map2 = new HashMap<>();
|
||||
private static Map<String, org.hl7.fhir.dstu2016may.model.StructureDefinition> map2b = new HashMap<>();
|
||||
|
||||
public static void main(String[] args) throws FileNotFoundException, ParserConfigurationException, SAXException, IOException {
|
||||
mod = 0;
|
||||
for (File f : new File(args[0]).listFiles()) {
|
||||
if (f.getName().startsWith("xver-")) {
|
||||
JsonObject j = JsonTrackingParser.parseJson(f);
|
||||
fixUp(j, f.getName());
|
||||
JsonTrackingParser.write(j, f, true);
|
||||
}
|
||||
}
|
||||
System.out.println("all done: "+mod+" modifiers");
|
||||
}
|
||||
|
||||
private static void fixUp(JsonObject j, String name) throws FHIRFormatError, FileNotFoundException, IOException {
|
||||
name = name.replace(".json", "");
|
||||
System.out.println("Process "+name);
|
||||
String version = name.substring(name.lastIndexOf("-")+1);
|
||||
int i = 0;
|
||||
for (Entry<String, JsonElement> e : j.entrySet()) {
|
||||
if (i == 50) {
|
||||
i = 0;
|
||||
System.out.print(".");
|
||||
}
|
||||
i++;
|
||||
String n = e.getKey();
|
||||
JsonObject o = ((JsonObject) e.getValue());
|
||||
boolean ok = (o.has("types") && o.getAsJsonArray("types").size() > 0) || (o.has("elements") && o.getAsJsonArray("elements").size() > 0);
|
||||
if (!ok) {
|
||||
List<String> types = new ArrayList<>();
|
||||
List<String> elements = new ArrayList<>();
|
||||
getElementInfo(version, n, types, elements);
|
||||
if (elements.size() > 0) {
|
||||
JsonArray arr = o.getAsJsonArray("elements");
|
||||
if (arr == null) {
|
||||
arr = new JsonArray();
|
||||
o.add("elements", arr);
|
||||
}
|
||||
for (String s : types) {
|
||||
arr.add(s);
|
||||
}
|
||||
} else if (types.size() > 0) {
|
||||
JsonArray arr = o.getAsJsonArray("types");
|
||||
if (arr == null) {
|
||||
arr = new JsonArray();
|
||||
o.add("types", arr);
|
||||
}
|
||||
for (String s : types) {
|
||||
arr.add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("done");
|
||||
}
|
||||
|
||||
private static boolean getElementInfo(String version, String n, List<String> types, List<String> elements) throws FHIRFormatError, FileNotFoundException, IOException {
|
||||
if ("contained".equals(n.substring(n.indexOf(".")+1))) {
|
||||
return false;
|
||||
}
|
||||
switch (version) {
|
||||
case "4.6": return getElementInfoR5(n, types, elements);
|
||||
case "4.0": return getElementInfoR4(n, types, elements);
|
||||
case "3.0": return getElementInfoR3(n, types, elements);
|
||||
case "1.4": return getElementInfoR2B(n, types, elements);
|
||||
case "1.0": return getElementInfoR2(n, types, elements);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Object tail(String value) {
|
||||
return value.contains("/") ? value.substring(value.lastIndexOf("/")+1) : value;
|
||||
}
|
||||
|
||||
private static boolean getElementInfoR5(String n, List<String> types, List<String> elements) throws FHIRFormatError, FileNotFoundException, IOException {
|
||||
String tn = n.substring(0, n.indexOf("."));
|
||||
org.hl7.fhir.r5.model.StructureDefinition sd = null;
|
||||
if (map5.containsKey(tn)) {
|
||||
sd = map5.get(tn);
|
||||
} else {
|
||||
sd = (org.hl7.fhir.r5.model.StructureDefinition) new org.hl7.fhir.r5.formats.JsonParser().parse(new FileInputStream(Utilities.path(R5_FOLDER, "StructureDefinition-"+tn+".json")));
|
||||
map5.put(tn, sd);
|
||||
}
|
||||
for (org.hl7.fhir.r5.model.ElementDefinition ed : sd.getSnapshot().getElement()) {
|
||||
if (ed.getPath().equals(n)) {
|
||||
List<org.hl7.fhir.r5.model.ElementDefinition> children = listChildrenR5(sd.getSnapshot().getElement(), ed);
|
||||
if (children.size() > 0) {
|
||||
for (org.hl7.fhir.r5.model.ElementDefinition c : children) {
|
||||
String en = c.getPath().substring(ed.getPath().length()+1);
|
||||
elements.add(en);
|
||||
}
|
||||
} else {
|
||||
for (org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent t : ed.getType()) {
|
||||
if (t.hasTargetProfile()) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append(t.getWorkingCode());
|
||||
b.append("(");
|
||||
boolean first = true;
|
||||
for (org.hl7.fhir.r5.model.CanonicalType u : t.getTargetProfile()) {
|
||||
if (first) first = false; else b.append("|");
|
||||
b.append(tail(u.getValue()));
|
||||
}
|
||||
b.append(")");
|
||||
types.add(b.toString());
|
||||
} else {
|
||||
types.add(t.getWorkingCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private static List<org.hl7.fhir.r5.model.ElementDefinition> listChildrenR5(List<org.hl7.fhir.r5.model.ElementDefinition> list, org.hl7.fhir.r5.model.ElementDefinition ed) {
|
||||
List<org.hl7.fhir.r5.model.ElementDefinition> res = new ArrayList<>();
|
||||
for (org.hl7.fhir.r5.model.ElementDefinition t : list) {
|
||||
String p = t.getPath();
|
||||
if (p.startsWith(ed.getPath()+".")) {
|
||||
p = p.substring(ed.getPath().length()+1);
|
||||
if (!p.contains(".")) {
|
||||
res.add(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private static boolean getElementInfoR4(String n, List<String> types, List<String> elements) throws FHIRFormatError, FileNotFoundException, IOException {
|
||||
String tn = n.substring(0, n.indexOf("."));
|
||||
org.hl7.fhir.r4.model.StructureDefinition sd = null;
|
||||
if (map4.containsKey(tn)) {
|
||||
sd = map4.get(tn);
|
||||
} else {
|
||||
sd = (org.hl7.fhir.r4.model.StructureDefinition) new org.hl7.fhir.r4.formats.JsonParser().parse(new FileInputStream(Utilities.path(R4_FOLDER, "StructureDefinition-"+tn+".json")));
|
||||
map4.put(tn, sd);
|
||||
}
|
||||
for (org.hl7.fhir.r4.model.ElementDefinition ed : sd.getSnapshot().getElement()) {
|
||||
if (ed.getPath().equals(n)) {
|
||||
List<org.hl7.fhir.r4.model.ElementDefinition> children = listChildrenR4(sd.getSnapshot().getElement(), ed);
|
||||
if (children.size() > 0) {
|
||||
for (org.hl7.fhir.r4.model.ElementDefinition c : children) {
|
||||
String en = c.getPath().substring(ed.getPath().length()+1);
|
||||
elements.add(en);
|
||||
}
|
||||
} else {
|
||||
for (org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent t : ed.getType()) {
|
||||
if (t.hasTargetProfile()) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append(t.getWorkingCode());
|
||||
b.append("(");
|
||||
boolean first = true;
|
||||
for (org.hl7.fhir.r4.model.CanonicalType u : t.getTargetProfile()) {
|
||||
if (first) first = false; else b.append("|");
|
||||
b.append(tail(u.getValue()));
|
||||
}
|
||||
b.append(")");
|
||||
types.add(b.toString());
|
||||
} else {
|
||||
types.add(t.getWorkingCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private static List<org.hl7.fhir.r4.model.ElementDefinition> listChildrenR4(List<org.hl7.fhir.r4.model.ElementDefinition> list, org.hl7.fhir.r4.model.ElementDefinition ed) {
|
||||
List<org.hl7.fhir.r4.model.ElementDefinition> res = new ArrayList<>();
|
||||
for (org.hl7.fhir.r4.model.ElementDefinition t : list) {
|
||||
String p = t.getPath();
|
||||
if (p.startsWith(ed.getPath()+".")) {
|
||||
p = p.substring(ed.getPath().length()+1);
|
||||
if (!p.contains(".")) {
|
||||
res.add(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
private static boolean getElementInfoR3(String n, List<String> types, List<String> elements) throws FHIRFormatError, FileNotFoundException, IOException {
|
||||
String tn = n.substring(0, n.indexOf("."));
|
||||
org.hl7.fhir.dstu3.model.StructureDefinition sd = null;
|
||||
if (map3.containsKey(tn)) {
|
||||
sd = map3.get(tn);
|
||||
} else {
|
||||
sd = (org.hl7.fhir.dstu3.model.StructureDefinition) new org.hl7.fhir.dstu3.formats.JsonParser().parse(new FileInputStream(Utilities.path(R3_FOLDER, "StructureDefinition-"+tn+".json")));
|
||||
map3.put(tn, sd);
|
||||
}
|
||||
for (org.hl7.fhir.dstu3.model.ElementDefinition ed : sd.getSnapshot().getElement()) {
|
||||
if (ed.getPath().equals(n)) {
|
||||
List<org.hl7.fhir.dstu3.model.ElementDefinition> children = listChildrenR3(sd.getSnapshot().getElement(), ed);
|
||||
if (children.size() > 0) {
|
||||
for (org.hl7.fhir.dstu3.model.ElementDefinition c : children) {
|
||||
String en = c.getPath().substring(ed.getPath().length()+1);
|
||||
elements.add(en);
|
||||
}
|
||||
} else {
|
||||
for (org.hl7.fhir.dstu3.model.ElementDefinition.TypeRefComponent t : ed.getType()) {
|
||||
if (t.hasTargetProfile()) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append(t.getCode());
|
||||
b.append("(");
|
||||
b.append(tail(t.getTargetProfile()));
|
||||
b.append(")");
|
||||
types.add(b.toString());
|
||||
} else {
|
||||
types.add(t.getCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private static List<org.hl7.fhir.dstu3.model.ElementDefinition> listChildrenR3(List<org.hl7.fhir.dstu3.model.ElementDefinition> list, org.hl7.fhir.dstu3.model.ElementDefinition ed) {
|
||||
List<org.hl7.fhir.dstu3.model.ElementDefinition> res = new ArrayList<>();
|
||||
for (org.hl7.fhir.dstu3.model.ElementDefinition t : list) {
|
||||
String p = t.getPath();
|
||||
if (p.startsWith(ed.getPath()+".")) {
|
||||
p = p.substring(ed.getPath().length()+1);
|
||||
if (!p.contains(".")) {
|
||||
res.add(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
private static boolean getElementInfoR2(String n, List<String> types, List<String> elements) throws FHIRFormatError, FileNotFoundException, IOException {
|
||||
String tn = n.substring(0, n.indexOf("."));
|
||||
org.hl7.fhir.dstu2.model.StructureDefinition sd = null;
|
||||
if (map2.containsKey(tn)) {
|
||||
sd = map2.get(tn);
|
||||
} else {
|
||||
sd = (org.hl7.fhir.dstu2.model.StructureDefinition) new org.hl7.fhir.dstu2.formats.JsonParser().parse(new FileInputStream(Utilities.path(R2_FOLDER, "StructureDefinition-"+tn+".json")));
|
||||
map2.put(tn, sd);
|
||||
}
|
||||
for (org.hl7.fhir.dstu2.model.ElementDefinition ed : sd.getSnapshot().getElement()) {
|
||||
if (ed.getPath().equals(n)) {
|
||||
List<org.hl7.fhir.dstu2.model.ElementDefinition> children = listChildrenR2(sd.getSnapshot().getElement(), ed);
|
||||
if (children.size() > 0) {
|
||||
for (org.hl7.fhir.dstu2.model.ElementDefinition c : children) {
|
||||
String en = c.getPath().substring(ed.getPath().length()+1);
|
||||
elements.add(en);
|
||||
}
|
||||
} else {
|
||||
for (org.hl7.fhir.dstu2.model.ElementDefinition.TypeRefComponent t : ed.getType()) {
|
||||
if (t.hasProfile()) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append(t.getCode());
|
||||
b.append("(");
|
||||
boolean first = true;
|
||||
for (org.hl7.fhir.dstu2.model.UriType u : t.getProfile()) {
|
||||
if (first) first = false; else b.append("|");
|
||||
b.append(tail(u.getValue()));
|
||||
}
|
||||
b.append(")");
|
||||
types.add(b.toString());
|
||||
} else {
|
||||
types.add(t.getCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private static List<org.hl7.fhir.dstu2.model.ElementDefinition> listChildrenR2(List<org.hl7.fhir.dstu2.model.ElementDefinition> list, org.hl7.fhir.dstu2.model.ElementDefinition ed) {
|
||||
List<org.hl7.fhir.dstu2.model.ElementDefinition> res = new ArrayList<>();
|
||||
for (org.hl7.fhir.dstu2.model.ElementDefinition t : list) {
|
||||
String p = t.getPath();
|
||||
if (p.startsWith(ed.getPath()+".")) {
|
||||
p = p.substring(ed.getPath().length()+1);
|
||||
if (!p.contains(".")) {
|
||||
res.add(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
private static boolean getElementInfoR2B(String n, List<String> types, List<String> elements) throws FHIRFormatError, FileNotFoundException, IOException {
|
||||
String tn = n.substring(0, n.indexOf("."));
|
||||
org.hl7.fhir.dstu2016may.model.StructureDefinition sd = null;
|
||||
if (map2b.containsKey(tn)) {
|
||||
sd = map2b.get(tn);
|
||||
} else {
|
||||
sd = (org.hl7.fhir.dstu2016may.model.StructureDefinition) new org.hl7.fhir.dstu2016may.formats.JsonParser().parse(new FileInputStream(Utilities.path(R2B_FOLDER, "StructureDefinition-"+tn+".json")));
|
||||
map2b.put(tn, sd);
|
||||
}
|
||||
for (org.hl7.fhir.dstu2016may.model.ElementDefinition ed : sd.getSnapshot().getElement()) {
|
||||
if (ed.getPath().equals(n)) {
|
||||
List<org.hl7.fhir.dstu2016may.model.ElementDefinition> children = listChildrenR2B(sd.getSnapshot().getElement(), ed);
|
||||
if (children.size() > 0) {
|
||||
for (org.hl7.fhir.dstu2016may.model.ElementDefinition c : children) {
|
||||
String en = c.getPath().substring(ed.getPath().length()+1);
|
||||
elements.add(en);
|
||||
}
|
||||
} else {
|
||||
for (org.hl7.fhir.dstu2016may.model.ElementDefinition.TypeRefComponent t : ed.getType()) {
|
||||
if (t.hasProfile()) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append(t.getCode());
|
||||
b.append("(");
|
||||
boolean first = true;
|
||||
for (org.hl7.fhir.dstu2016may.model.UriType u : t.getProfile()) {
|
||||
if (first) first = false; else b.append("|");
|
||||
b.append(tail(u.getValue()));
|
||||
}
|
||||
b.append(")");
|
||||
types.add(b.toString());
|
||||
} else {
|
||||
types.add(t.getCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private static List<org.hl7.fhir.dstu2016may.model.ElementDefinition> listChildrenR2B(List<org.hl7.fhir.dstu2016may.model.ElementDefinition> list, org.hl7.fhir.dstu2016may.model.ElementDefinition ed) {
|
||||
List<org.hl7.fhir.dstu2016may.model.ElementDefinition> res = new ArrayList<>();
|
||||
for (org.hl7.fhir.dstu2016may.model.ElementDefinition t : list) {
|
||||
String p = t.getPath();
|
||||
if (p.startsWith(ed.getPath()+".")) {
|
||||
p = p.substring(ed.getPath().length()+1);
|
||||
if (!p.contains(".")) {
|
||||
res.add(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>5.5.12-SNAPSHOT</version>
|
||||
<version>5.6.16-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ import org.hl7.fhir.dstu2.model.ValueSet.ConceptDefinitionComponent;
|
|||
import org.hl7.fhir.dstu2.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.dstu2.model.ValueSet.ValueSetExpansionComponent;
|
||||
import org.hl7.fhir.dstu2.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
|
||||
import org.hl7.fhir.dstu2.utils.validation.IResourceValidator;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@ import org.hl7.fhir.dstu2.model.ValueSet;
|
|||
import org.hl7.fhir.dstu2.terminologies.ValueSetExpansionCache;
|
||||
import org.hl7.fhir.dstu2.utils.ProfileUtilities.ProfileKnowledgeProvider;
|
||||
import org.hl7.fhir.dstu2.utils.client.FHIRToolingClient;
|
||||
import org.hl7.fhir.dstu2.utils.validation.IResourceValidator;
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.utilities.CSFileInputStream;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package org.hl7.fhir.dstu2.utils;
|
||||
package org.hl7.fhir.dstu2.utils.validation;
|
||||
|
||||
/*
|
||||
Copyright (c) 2011+, HL7, Inc.
|
||||
|
@ -34,6 +34,9 @@ package org.hl7.fhir.dstu2.utils;
|
|||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.dstu2.model.StructureDefinition;
|
||||
import org.hl7.fhir.dstu2.utils.validation.constants.BestPracticeWarningLevel;
|
||||
import org.hl7.fhir.dstu2.utils.validation.constants.CheckDisplayOption;
|
||||
import org.hl7.fhir.dstu2.utils.validation.constants.IdStatus;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
@ -42,29 +45,6 @@ import com.google.gson.JsonObject;
|
|||
|
||||
public interface IResourceValidator {
|
||||
|
||||
/**
|
||||
* whether the validator should enforce best practice guidelines
|
||||
* as defined by various HL7 committees
|
||||
*
|
||||
*
|
||||
* @author Grahame Grieve
|
||||
*
|
||||
*/
|
||||
public enum BestPracticeWarningLevel {
|
||||
Ignore,
|
||||
Hint,
|
||||
Warning,
|
||||
Error
|
||||
}
|
||||
|
||||
public enum CheckDisplayOption {
|
||||
Ignore,
|
||||
Check,
|
||||
CheckCaseAndSpace,
|
||||
CheckCase,
|
||||
CheckSpace
|
||||
}
|
||||
|
||||
/**
|
||||
* how much to check displays for coded elements
|
||||
* @return
|
||||
|
@ -77,10 +57,6 @@ public interface IResourceValidator {
|
|||
*/
|
||||
void setCheckDisplay(CheckDisplayOption checkDisplay);
|
||||
|
||||
enum IdStatus {
|
||||
OPTIONAL, REQUIRED, PROHIBITED
|
||||
}
|
||||
|
||||
/**
|
||||
* whether the resource must have an id or not (depends on context)
|
||||
*
|
||||
|
@ -93,39 +69,26 @@ public interface IResourceValidator {
|
|||
BestPracticeWarningLevel getBasePracticeWarningLevel();
|
||||
void setBestPracticeWarningLevel(BestPracticeWarningLevel value);
|
||||
|
||||
|
||||
/**
|
||||
* Given a DOM element, return a list of errors in the resource
|
||||
*
|
||||
* @param errors
|
||||
* @param elem
|
||||
* @- if the underlying infrastructure fails (not if the resource is invalid)
|
||||
*/
|
||||
void validate(List<ValidationMessage> errors, Element element) throws Exception;
|
||||
|
||||
/**
|
||||
* Given a JSON Object, return a list of errors in the resource
|
||||
*
|
||||
* @param errors
|
||||
* @param elem
|
||||
* @- if the underlying infrastructure fails (not if the resource is invalid)
|
||||
*/
|
||||
void validate(List<ValidationMessage> errors, JsonObject object) throws Exception;
|
||||
|
||||
/**
|
||||
* Given a DOM element, return a list of errors in the resource
|
||||
*
|
||||
* @param errors
|
||||
* @param elem
|
||||
* @- if the underlying infrastructure fails (not if the resource is invalid)
|
||||
*/
|
||||
List<ValidationMessage> validate(Element element) throws Exception;
|
||||
|
||||
/**
|
||||
* Given a DOM element, return a list of errors in the resource
|
||||
*
|
||||
* @param errors
|
||||
* @param elem
|
||||
* @- if the underlying infrastructure fails (not if the resource is invalid)
|
||||
*/
|
||||
List<ValidationMessage> validate(JsonObject object) throws Exception;
|
||||
|
@ -133,10 +96,6 @@ public interface IResourceValidator {
|
|||
/**
|
||||
* Given a DOM element, return a list of errors in the resource
|
||||
* with regard to the specified profile (by logical identifier)
|
||||
*
|
||||
* @param errors
|
||||
* @param element
|
||||
* @param profile
|
||||
* @- if the underlying infrastructure fails, or the profile can't be found (not if the resource is invalid)
|
||||
*/
|
||||
void validate(List<ValidationMessage> errors, Element element, String profile) throws Exception;
|
||||
|
@ -144,10 +103,6 @@ public interface IResourceValidator {
|
|||
/**
|
||||
* Given a DOM element, return a list of errors in the resource
|
||||
* with regard to the specified profile (by logical identifier)
|
||||
*
|
||||
* @param errors
|
||||
* @param element
|
||||
* @param profile
|
||||
* @- if the underlying infrastructure fails, or the profile can't be found (not if the resource is invalid)
|
||||
*/
|
||||
List<ValidationMessage> validate(Element element, String profile) throws Exception;
|
||||
|
@ -155,10 +110,6 @@ public interface IResourceValidator {
|
|||
/**
|
||||
* Given a DOM element, return a list of errors in the resource
|
||||
* with regard to the specified profile (by logical identifier)
|
||||
*
|
||||
* @param errors
|
||||
* @param element
|
||||
* @param profile
|
||||
* @- if the underlying infrastructure fails, or the profile can't be found (not if the resource is invalid)
|
||||
*/
|
||||
List<ValidationMessage> validate(JsonObject object, StructureDefinition profile) throws Exception;
|
||||
|
@ -166,10 +117,6 @@ public interface IResourceValidator {
|
|||
/**
|
||||
* Given a DOM element, return a list of errors in the resource
|
||||
* with regard to the specified profile (by logical identifier)
|
||||
*
|
||||
* @param errors
|
||||
* @param element
|
||||
* @param profile
|
||||
* @- if the underlying infrastructure fails, or the profile can't be found (not if the resource is invalid)
|
||||
*/
|
||||
List<ValidationMessage> validate(JsonObject object, String profile) throws Exception;
|
||||
|
@ -177,10 +124,6 @@ public interface IResourceValidator {
|
|||
/**
|
||||
* Given a DOM element, return a list of errors in the resource
|
||||
* with regard to the specified profile
|
||||
*
|
||||
* @param errors
|
||||
* @param element
|
||||
* @param profile
|
||||
* @- if the underlying infrastructure fails (not if the resource is invalid)
|
||||
*/
|
||||
void validate(List<ValidationMessage> errors, Element element, StructureDefinition profile) throws Exception;
|
||||
|
@ -188,10 +131,6 @@ public interface IResourceValidator {
|
|||
/**
|
||||
* Given a DOM element, return a list of errors in the resource
|
||||
* with regard to the specified profile
|
||||
*
|
||||
* @param errors
|
||||
* @param element
|
||||
* @param profile
|
||||
* @- if the underlying infrastructure fails (not if the resource is invalid)
|
||||
*/
|
||||
void validate(List<ValidationMessage> errors, JsonObject object, StructureDefinition profile) throws Exception;
|
||||
|
@ -199,10 +138,6 @@ public interface IResourceValidator {
|
|||
/**
|
||||
* Given a DOM element, return a list of errors in the resource
|
||||
* with regard to the specified profile
|
||||
*
|
||||
* @param errors
|
||||
* @param element
|
||||
* @param profile
|
||||
* @- if the underlying infrastructure fails (not if the resource is invalid)
|
||||
*/
|
||||
void validate(List<ValidationMessage> errors, JsonObject object, String profile) throws Exception;
|
||||
|
@ -210,10 +145,6 @@ public interface IResourceValidator {
|
|||
/**
|
||||
* Given a DOM element, return a list of errors in the resource
|
||||
* with regard to the specified profile
|
||||
*
|
||||
* @param errors
|
||||
* @param element
|
||||
* @param profile
|
||||
* @- if the underlying infrastructure fails (not if the resource is invalid)
|
||||
*/
|
||||
List<ValidationMessage> validate(Element element, StructureDefinition profile) throws Exception;
|
||||
|
@ -221,18 +152,12 @@ public interface IResourceValidator {
|
|||
|
||||
/**
|
||||
* Given a DOM document, return a list of errors in the resource
|
||||
*
|
||||
* @param errors
|
||||
* @param elem
|
||||
* @- if the underlying infrastructure fails (not if the resource is invalid)
|
||||
*/
|
||||
void validate(List<ValidationMessage> errors, Document document) throws Exception;
|
||||
|
||||
/**
|
||||
* Given a DOM document, return a list of errors in the resource
|
||||
*
|
||||
* @param errors
|
||||
* @param elem
|
||||
* @- if the underlying infrastructure fails (not if the resource is invalid)
|
||||
*/
|
||||
List<ValidationMessage> validate(Document document) throws Exception;
|
||||
|
@ -240,10 +165,6 @@ public interface IResourceValidator {
|
|||
/**
|
||||
* Given a DOM document, return a list of errors in the resource
|
||||
* with regard to the specified profile (by logical identifier)
|
||||
*
|
||||
* @param errors
|
||||
* @param element
|
||||
* @param profile
|
||||
* @- if the underlying infrastructure fails, or the profile can't be found (not if the resource is invalid)
|
||||
*/
|
||||
void validate(List<ValidationMessage> errors, Document document, String profile) throws Exception;
|
||||
|
@ -251,10 +172,6 @@ public interface IResourceValidator {
|
|||
/**
|
||||
* Given a DOM document, return a list of errors in the resource
|
||||
* with regard to the specified profile (by logical identifier)
|
||||
*
|
||||
* @param errors
|
||||
* @param element
|
||||
* @param profile
|
||||
* @- if the underlying infrastructure fails, or the profile can't be found (not if the resource is invalid)
|
||||
*/
|
||||
List<ValidationMessage> validate(Document document, String profile) throws Exception;
|
||||
|
@ -262,10 +179,6 @@ public interface IResourceValidator {
|
|||
/**
|
||||
* Given a DOM document, return a list of errors in the resource
|
||||
* with regard to the specified profile
|
||||
*
|
||||
* @param errors
|
||||
* @param element
|
||||
* @param profile
|
||||
* @- if the underlying infrastructure fails (not if the resource is invalid)
|
||||
*/
|
||||
void validate(List<ValidationMessage> errors, Document document, StructureDefinition profile) throws Exception;
|
||||
|
@ -273,10 +186,6 @@ public interface IResourceValidator {
|
|||
/**
|
||||
* Given a DOM document, return a list of errors in the resource
|
||||
* with regard to the specified profile
|
||||
*
|
||||
* @param errors
|
||||
* @param element
|
||||
* @param profile
|
||||
* @- if the underlying infrastructure fails (not if the resource is invalid)
|
||||
*/
|
||||
List<ValidationMessage> validate(Document document, StructureDefinition profile) throws Exception;
|
|
@ -0,0 +1,12 @@
|
|||
package org.hl7.fhir.dstu2.utils.validation.constants;
|
||||
|
||||
/**
|
||||
* whether the validator should enforce best practice guidelines
|
||||
* as defined by various HL7 committees
|
||||
*/
|
||||
public enum BestPracticeWarningLevel {
|
||||
Ignore,
|
||||
Hint,
|
||||
Warning,
|
||||
Error
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package org.hl7.fhir.dstu2.utils.validation.constants;
|
||||
|
||||
public enum CheckDisplayOption {
|
||||
Ignore,
|
||||
Check,
|
||||
CheckCaseAndSpace,
|
||||
CheckCase,
|
||||
CheckSpace
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package org.hl7.fhir.dstu2.utils.validation.constants;
|
||||
|
||||
public enum IdStatus {
|
||||
OPTIONAL,
|
||||
REQUIRED,
|
||||
PROHIBITED
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>5.5.12-SNAPSHOT</version>
|
||||
<version>5.6.16-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>5.5.12-SNAPSHOT</version>
|
||||
<version>5.6.16-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionComponent;
|
|||
import org.hl7.fhir.dstu3.terminologies.ValueSetExpander.TerminologyServiceErrorClass;
|
||||
import org.hl7.fhir.dstu3.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
|
||||
import org.hl7.fhir.dstu3.utils.INarrativeGenerator;
|
||||
import org.hl7.fhir.dstu3.utils.IResourceValidator;
|
||||
import org.hl7.fhir.dstu3.utils.validation.IResourceValidator;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.TerminologyServiceException;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
|
|
|
@ -80,7 +80,7 @@ import org.hl7.fhir.dstu3.model.StructureMap.StructureMapStructureComponent;
|
|||
import org.hl7.fhir.dstu3.model.ValueSet;
|
||||
import org.hl7.fhir.dstu3.terminologies.ValueSetExpansionCache;
|
||||
import org.hl7.fhir.dstu3.utils.INarrativeGenerator;
|
||||
import org.hl7.fhir.dstu3.utils.IResourceValidator;
|
||||
import org.hl7.fhir.dstu3.utils.validation.IResourceValidator;
|
||||
import org.hl7.fhir.dstu3.utils.NarrativeGenerator;
|
||||
import org.hl7.fhir.dstu3.utils.client.FHIRToolingClient;
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
|
|
|
@ -206,14 +206,19 @@ public class FhirRequestBuilder {
|
|||
|
||||
public <T extends Resource> ResourceRequest<T> execute() throws IOException {
|
||||
formatHeaders(httpRequest, resourceFormat, headers);
|
||||
Response response = getHttpClient().newCall(httpRequest.build()).execute();
|
||||
final Request request = httpRequest.build();
|
||||
log(request.method(), request.url().toString(), request.headers(), request.body() != null ? request.body().toString().getBytes() : null);
|
||||
Response response = getHttpClient().newCall(request).execute();
|
||||
T resource = unmarshalReference(response, resourceFormat);
|
||||
return new ResourceRequest<T>(resource, response.code(), getLocationHeader(response.headers()));
|
||||
}
|
||||
|
||||
public Bundle executeAsBatch() throws IOException {
|
||||
formatHeaders(httpRequest, resourceFormat, null);
|
||||
Response response = getHttpClient().newCall(httpRequest.build()).execute();
|
||||
final Request request = httpRequest.build();
|
||||
log(request.method(), request.url().toString(), request.headers(), request.body() != null ? request.body().toString().getBytes() : null);
|
||||
|
||||
Response response = getHttpClient().newCall(request).execute();
|
||||
return unmarshalFeed(response, resourceFormat);
|
||||
}
|
||||
|
||||
|
@ -302,6 +307,26 @@ public class FhirRequestBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the given {@link Request}, using the current {@link ToolingClientLogger}. If the current
|
||||
* {@link FhirRequestBuilder#logger} is null, no action is taken.
|
||||
*
|
||||
* @param method HTTP request method
|
||||
* @param url request URL
|
||||
* @param requestHeaders {@link Headers} for request
|
||||
* @param requestBody Byte array request
|
||||
*/
|
||||
protected void log(String method, String url, Headers requestHeaders, byte[] requestBody) {
|
||||
if (logger != null) {
|
||||
List<String> headerList = new ArrayList<>(Collections.emptyList());
|
||||
Map<String, List<String>> headerMap = requestHeaders.toMultimap();
|
||||
headerMap.keySet().forEach(key -> headerMap.get(key).forEach(value -> headerList.add(key + ":" + value)));
|
||||
|
||||
logger.logRequest(method, url, headerList, requestBody);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the given {@link Response}, using the current {@link ToolingClientLogger}. If the current
|
||||
* {@link FhirRequestBuilder#logger} is null, no action is taken.
|
||||
|
|
|
@ -34,8 +34,8 @@ public class RetryInterceptor implements Interceptor {
|
|||
try {
|
||||
// If we are retrying a failed request that failed due to a bad response from the server, we must close it first
|
||||
if (response != null) {
|
||||
System.out.println("Previous " + chain.request().method() + " attempt returned HTTP<" + (response.code())
|
||||
+ "> from url -> " + chain.request().url() + ".");
|
||||
// System.out.println("Previous " + chain.request().method() + " attempt returned HTTP<" + (response.code())
|
||||
// + "> from url -> " + chain.request().url() + ".");
|
||||
response.close();
|
||||
}
|
||||
// System.out.println(chain.request().method() + " attempt <" + (retryCounter + 1) + "> to url -> " + chain.request().url());
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package org.hl7.fhir.dstu3.utils;
|
||||
package org.hl7.fhir.dstu3.utils.validation;
|
||||
|
||||
/*
|
||||
Copyright (c) 2011+, HL7, Inc.
|
||||
|
@ -30,21 +30,20 @@ package org.hl7.fhir.dstu3.utils;
|
|||
*/
|
||||
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import org.hl7.fhir.dstu3.elementmodel.Manager.FhirFormat;
|
||||
import org.hl7.fhir.dstu3.model.StructureDefinition;
|
||||
import org.hl7.fhir.dstu3.utils.ValidationProfileSet;
|
||||
import org.hl7.fhir.dstu3.utils.validation.constants.BestPracticeWarningLevel;
|
||||
import org.hl7.fhir.dstu3.utils.validation.constants.CheckDisplayOption;
|
||||
import org.hl7.fhir.dstu3.utils.validation.constants.IdStatus;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.dstu3.elementmodel.Element;
|
||||
import org.hl7.fhir.dstu3.elementmodel.Manager.FhirFormat;
|
||||
import org.hl7.fhir.dstu3.model.StructureDefinition;
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
/**
|
||||
* Interface to the instance validator. This takes a resource, in one of many forms, and
|
||||
* checks whether it is valid
|
||||
|
@ -54,49 +53,6 @@ import com.google.gson.JsonObject;
|
|||
*/
|
||||
public interface IResourceValidator {
|
||||
|
||||
public enum ReferenceValidationPolicy {
|
||||
IGNORE, CHECK_TYPE_IF_EXISTS, CHECK_EXISTS, CHECK_EXISTS_AND_TYPE, CHECK_VALID;
|
||||
|
||||
public boolean checkExists() {
|
||||
return this == CHECK_EXISTS_AND_TYPE || this == CHECK_EXISTS || this == CHECK_VALID;
|
||||
}
|
||||
|
||||
public boolean checkType() {
|
||||
return this == CHECK_TYPE_IF_EXISTS || this == CHECK_EXISTS_AND_TYPE || this == CHECK_VALID;
|
||||
}
|
||||
|
||||
public boolean checkValid() {
|
||||
return this == CHECK_VALID;
|
||||
}
|
||||
}
|
||||
|
||||
public interface IValidatorResourceFetcher {
|
||||
Element fetch(Object appContext, String url) throws FHIRFormatError, DefinitionException, IOException, FHIRException;
|
||||
ReferenceValidationPolicy validationPolicy(Object appContext, String path, String url);
|
||||
boolean resolveURL(Object appContext, String path, String url) throws IOException, FHIRException;
|
||||
}
|
||||
|
||||
public enum BestPracticeWarningLevel {
|
||||
Ignore,
|
||||
Hint,
|
||||
Warning,
|
||||
Error
|
||||
}
|
||||
|
||||
public enum CheckDisplayOption {
|
||||
Ignore,
|
||||
Check,
|
||||
CheckCaseAndSpace,
|
||||
CheckCase,
|
||||
CheckSpace
|
||||
}
|
||||
|
||||
enum IdStatus {
|
||||
OPTIONAL, REQUIRED, PROHIBITED
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* how much to check displays for coded elements
|
||||
* @return
|
||||
|
@ -124,21 +80,24 @@ public interface IResourceValidator {
|
|||
IValidatorResourceFetcher getFetcher();
|
||||
IResourceValidator setFetcher(IValidatorResourceFetcher value);
|
||||
|
||||
IValidationPolicyAdvisor getPolicyAdvisor();
|
||||
IResourceValidator setPolicyAdvisor(IValidationPolicyAdvisor advisor);
|
||||
|
||||
boolean isNoBindingMsgSuppressed();
|
||||
IResourceValidator setNoBindingMsgSuppressed(boolean noBindingMsgSuppressed);
|
||||
|
||||
public boolean isNoInvariantChecks();
|
||||
public IResourceValidator setNoInvariantChecks(boolean value) ;
|
||||
boolean isNoInvariantChecks();
|
||||
IResourceValidator setNoInvariantChecks(boolean value) ;
|
||||
|
||||
public boolean isNoTerminologyChecks();
|
||||
public IResourceValidator setNoTerminologyChecks(boolean noTerminologyChecks);
|
||||
boolean isNoTerminologyChecks();
|
||||
IResourceValidator setNoTerminologyChecks(boolean noTerminologyChecks);
|
||||
|
||||
/**
|
||||
* Whether being unable to resolve a profile in found in Resource.meta.profile or ElementDefinition.type.profile or targetProfile is an error or just a warning
|
||||
* @return
|
||||
*/
|
||||
public boolean isErrorForUnknownProfiles();
|
||||
public void setErrorForUnknownProfiles(boolean errorForUnknownProfiles);
|
||||
boolean isErrorForUnknownProfiles();
|
||||
void setErrorForUnknownProfiles(boolean errorForUnknownProfiles);
|
||||
|
||||
/**
|
||||
* Validate suite
|
|
@ -0,0 +1,21 @@
|
|||
package org.hl7.fhir.dstu3.utils.validation;
|
||||
|
||||
import org.hl7.fhir.dstu3.elementmodel.Element;
|
||||
import org.hl7.fhir.dstu3.utils.validation.constants.ReferenceValidationPolicy;
|
||||
|
||||
public interface IValidationPolicyAdvisor {
|
||||
|
||||
ReferenceValidationPolicy policyForReference(IResourceValidator validator,
|
||||
Object appContext,
|
||||
String path,
|
||||
String url);
|
||||
|
||||
ReferenceValidationPolicy policyForContained(IResourceValidator validator,
|
||||
Object appContext,
|
||||
String containerType,
|
||||
String containerId,
|
||||
Element.SpecialElement containingResourceType,
|
||||
String path,
|
||||
String url);
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package org.hl7.fhir.dstu3.utils.validation;
|
||||
|
||||
import org.hl7.fhir.dstu3.elementmodel.Element;
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface IValidatorResourceFetcher {
|
||||
Element fetch(Object appContext, String url) throws IOException, FHIRException;
|
||||
boolean resolveURL(Object appContext, String path, String url) throws IOException, FHIRException;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package org.hl7.fhir.dstu3.utils.validation.constants;
|
||||
|
||||
public enum BestPracticeWarningLevel {
|
||||
Ignore,
|
||||
Hint,
|
||||
Warning,
|
||||
Error
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package org.hl7.fhir.dstu3.utils.validation.constants;
|
||||
|
||||
public enum CheckDisplayOption {
|
||||
Ignore,
|
||||
Check,
|
||||
CheckCaseAndSpace,
|
||||
CheckCase,
|
||||
CheckSpace
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package org.hl7.fhir.dstu3.utils.validation.constants;
|
||||
|
||||
public enum IdStatus {
|
||||
OPTIONAL,
|
||||
REQUIRED,
|
||||
PROHIBITED
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package org.hl7.fhir.dstu3.utils.validation.constants;
|
||||
|
||||
public enum ReferenceValidationPolicy {
|
||||
IGNORE,
|
||||
CHECK_TYPE_IF_EXISTS,
|
||||
CHECK_EXISTS,
|
||||
CHECK_EXISTS_AND_TYPE,
|
||||
CHECK_VALID;
|
||||
|
||||
public boolean checkExists() {
|
||||
return this == CHECK_EXISTS_AND_TYPE || this == CHECK_EXISTS || this == CHECK_VALID;
|
||||
}
|
||||
|
||||
public boolean checkType() {
|
||||
return this == CHECK_TYPE_IF_EXISTS || this == CHECK_EXISTS_AND_TYPE || this == CHECK_VALID;
|
||||
}
|
||||
|
||||
public boolean checkValid() {
|
||||
return this == CHECK_VALID;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
package org.hl7.fhir.dstu3.utils.client.network;
|
||||
|
||||
import okhttp3.*;
|
||||
import org.hl7.fhir.dstu3.formats.IParser;
|
||||
|
||||
import org.hl7.fhir.utilities.ToolingClientLogger;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.AdditionalMatchers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import java.io.IOException;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class FhirRequestBuilderTests {
|
||||
|
||||
private static final String DUMMY_URL = "https://some-url.com/";
|
||||
|
||||
Request mockRequest = new Request.Builder()
|
||||
.url(DUMMY_URL)
|
||||
.build();
|
||||
|
||||
final String RESPONSE_BODY_STRING = "{}";
|
||||
|
||||
Response response = new Response.Builder()
|
||||
.request(mockRequest)
|
||||
.protocol(Protocol.HTTP_2)
|
||||
.code(200) // status code
|
||||
.message("")
|
||||
.body(ResponseBody.create(RESPONSE_BODY_STRING,
|
||||
MediaType.get("application/json; charset=utf-8")
|
||||
))
|
||||
.addHeader("Content-Type", "")
|
||||
.build();
|
||||
|
||||
final Request.Builder requestBuilder = new Request.Builder()
|
||||
.url(DUMMY_URL);
|
||||
|
||||
final FhirRequestBuilder fhirRequestBuilder = Mockito.spy(new FhirRequestBuilder(requestBuilder));
|
||||
|
||||
@Mock
|
||||
OkHttpClient client;
|
||||
|
||||
@Mock
|
||||
Call mockCall;
|
||||
|
||||
@Mock
|
||||
ToolingClientLogger logger;
|
||||
|
||||
@BeforeEach
|
||||
public void beforeEach() {
|
||||
Mockito.doReturn(client).when(fhirRequestBuilder).getHttpClient();
|
||||
fhirRequestBuilder.withLogger(logger);
|
||||
}
|
||||
|
||||
@Nested
|
||||
class RequestLoggingTests {
|
||||
|
||||
@BeforeEach
|
||||
public void beforeEach() throws IOException {
|
||||
Mockito.doReturn(response).when(mockCall).execute();
|
||||
Mockito.doReturn(mockCall).when(client).newCall(ArgumentMatchers.any());
|
||||
|
||||
Mockito.doReturn(null).when(fhirRequestBuilder).unmarshalReference(ArgumentMatchers.any(), ArgumentMatchers.isNull());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecuteLogging() throws IOException {
|
||||
fhirRequestBuilder.execute();
|
||||
Mockito.verify(logger).logRequest(ArgumentMatchers.eq("GET"), ArgumentMatchers.eq(DUMMY_URL), ArgumentMatchers.anyList(), ArgumentMatchers.isNull());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecuteBatchLogging() throws IOException {
|
||||
fhirRequestBuilder.executeAsBatch();
|
||||
Mockito.verify(logger).logRequest(ArgumentMatchers.eq("GET"), ArgumentMatchers.eq(DUMMY_URL), ArgumentMatchers.anyList(), ArgumentMatchers.isNull());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnmarshallReferenceLogging() {
|
||||
IParser parser = Mockito.mock(IParser.class);
|
||||
Mockito.doReturn(parser).when(fhirRequestBuilder).getParser(ArgumentMatchers.eq("json"));
|
||||
|
||||
fhirRequestBuilder.unmarshalReference(response, "json");
|
||||
Mockito.verify(logger).logResponse(ArgumentMatchers.eq("200"), ArgumentMatchers.anyList(), AdditionalMatchers.aryEq(RESPONSE_BODY_STRING.getBytes()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnmarshallFeedLogging() {
|
||||
fhirRequestBuilder.unmarshalFeed(response, "application/json");
|
||||
Mockito.verify(logger).logResponse(ArgumentMatchers.eq("200"), ArgumentMatchers.anyList(), AdditionalMatchers.aryEq(RESPONSE_BODY_STRING.getBytes()));
|
||||
}
|
||||
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>5.5.12-SNAPSHOT</version>
|
||||
<version>5.6.16-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@ package org.hl7.fhir.r4.context;
|
|||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.fhir.ucum.UcumService;
|
||||
|
@ -58,8 +57,7 @@ import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
|
|||
import org.hl7.fhir.r4.terminologies.ValueSetExpander.TerminologyServiceErrorClass;
|
||||
import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
|
||||
import org.hl7.fhir.r4.utils.INarrativeGenerator;
|
||||
import org.hl7.fhir.r4.utils.IResourceValidator;
|
||||
import org.hl7.fhir.utilities.TerminologyServiceOptions;
|
||||
import org.hl7.fhir.r4.utils.validation.IResourceValidator;
|
||||
import org.hl7.fhir.utilities.TranslationServices;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
import org.hl7.fhir.utilities.validation.ValidationOptions;
|
||||
|
|
|
@ -75,7 +75,7 @@ import org.hl7.fhir.r4.model.StructureMap.StructureMapModelMode;
|
|||
import org.hl7.fhir.r4.model.StructureMap.StructureMapStructureComponent;
|
||||
import org.hl7.fhir.r4.terminologies.TerminologyClient;
|
||||
import org.hl7.fhir.r4.utils.INarrativeGenerator;
|
||||
import org.hl7.fhir.r4.utils.IResourceValidator;
|
||||
import org.hl7.fhir.r4.utils.validation.IResourceValidator;
|
||||
import org.hl7.fhir.r4.utils.NarrativeGenerator;
|
||||
import org.hl7.fhir.utilities.CSFileInputStream;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
|
|
|
@ -10036,6 +10036,7 @@ The primary difference between a medication statement and a medication administr
|
|||
* R4B - manually added
|
||||
*/
|
||||
_4_1_0,
|
||||
_4_3_0_CIBUILD,
|
||||
NULL;
|
||||
public static FHIRVersion fromCode(String codeString) throws FHIRException {
|
||||
if (codeString == null || "".equals(codeString))
|
||||
|
@ -10088,6 +10089,8 @@ The primary difference between a medication statement and a medication administr
|
|||
return _4_0_1;
|
||||
if ("4.1.0".equals(codeString))
|
||||
return _4_1_0;
|
||||
if ("4.3.0-CIBUILD".equals(codeString))
|
||||
return _4_3_0_CIBUILD;
|
||||
throw new FHIRException("Unknown FHIRVersion code '"+codeString+"'");
|
||||
}
|
||||
@Override
|
||||
|
@ -10120,6 +10123,8 @@ The primary difference between a medication statement and a medication administr
|
|||
case _4_0_0: return "4.0.0";
|
||||
case _4_0_1: return "4.0.1";
|
||||
case _4_1_0: return "4.1.0";
|
||||
case _4_3_0_CIBUILD: return "4.3.0-CIBUILD";
|
||||
|
||||
case NULL: return null;
|
||||
default: return "?";
|
||||
}
|
||||
|
@ -10150,6 +10155,7 @@ The primary difference between a medication statement and a medication administr
|
|||
case _4_0_0: return "http://hl7.org/fhir/FHIR-version";
|
||||
case _4_0_1: return "http://hl7.org/fhir/FHIR-version";
|
||||
case _4_1_0: return "http://hl7.org/fhir/FHIR-version";
|
||||
case _4_3_0_CIBUILD: return "http://hl7.org/fhir/FHIR-version";
|
||||
case NULL: return null;
|
||||
default: return "?";
|
||||
}
|
||||
|
@ -10179,7 +10185,8 @@ The primary difference between a medication statement and a medication administr
|
|||
case _3_5_0: return "R4 Ballot #2.";
|
||||
case _4_0_0: return "FHIR Release 4 (Normative + STU).";
|
||||
case _4_0_1: return "FHIR Release 4 Technical Correction #1.";
|
||||
case _4_1_0: return "FHIR Release 4B";
|
||||
case _4_1_0: return "FHIR Release 4B Ballot #1";
|
||||
case _4_3_0_CIBUILD: return "FHIR Release 4B CI-Builld";
|
||||
case NULL: return null;
|
||||
default: return "?";
|
||||
}
|
||||
|
@ -10210,6 +10217,7 @@ The primary difference between a medication statement and a medication administr
|
|||
case _4_0_0: return "4.0.0";
|
||||
case _4_0_1: return "4.0.1";
|
||||
case _4_1_0: return "4.1.0";
|
||||
case _4_3_0_CIBUILD: return "4.3.0-CIBUILD";
|
||||
case NULL: return null;
|
||||
default: return "?";
|
||||
}
|
||||
|
@ -10275,6 +10283,8 @@ The primary difference between a medication statement and a medication administr
|
|||
return FHIRVersion._4_0_1;
|
||||
if ("4.1.0".equals(codeString))
|
||||
return FHIRVersion._4_1_0;
|
||||
if ("4.3.0-CIBUILD".equals(codeString))
|
||||
return FHIRVersion._4_3_0_CIBUILD;
|
||||
throw new IllegalArgumentException("Unknown FHIRVersion code '"+codeString+"'");
|
||||
}
|
||||
public Enumeration<FHIRVersion> fromType(Base code) throws FHIRException {
|
||||
|
@ -10333,6 +10343,8 @@ The primary difference between a medication statement and a medication administr
|
|||
return new Enumeration<FHIRVersion>(this, FHIRVersion._4_0_1);
|
||||
if ("4.1.0".equals(codeString))
|
||||
return new Enumeration<FHIRVersion>(this, FHIRVersion._4_1_0);
|
||||
if ("4.3.0-CIBUILD".equals(codeString))
|
||||
return new Enumeration<FHIRVersion>(this, FHIRVersion._4_3_0_CIBUILD);
|
||||
throw new FHIRException("Unknown FHIRVersion code '"+codeString+"'");
|
||||
}
|
||||
public String toCode(FHIRVersion code) {
|
||||
|
@ -10384,6 +10396,8 @@ The primary difference between a medication statement and a medication administr
|
|||
return "4.0.1";
|
||||
if (code == FHIRVersion._4_1_0)
|
||||
return "4.1.0";
|
||||
if (code == FHIRVersion._4_3_0_CIBUILD)
|
||||
return "4.3.0_CIBUILD";
|
||||
return "?";
|
||||
}
|
||||
public String toSystem(FHIRVersion code) {
|
||||
|
|
|
@ -115,6 +115,7 @@ import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent;
|
|||
import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
|
||||
import org.hl7.fhir.r4.utils.FHIRLexer.FHIRLexerException;
|
||||
import org.hl7.fhir.r4.utils.FHIRPathEngine.IEvaluationContext;
|
||||
import org.hl7.fhir.r4.utils.validation.IResourceValidator;
|
||||
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
|
||||
import org.hl7.fhir.utilities.TerminologyServiceOptions;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
|
|
|
@ -2,8 +2,8 @@ package org.hl7.fhir.r4.utils.client.network;
|
|||
|
||||
import okhttp3.*;
|
||||
import org.hl7.fhir.utilities.ToolingClientLogger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -22,9 +22,8 @@ public class FhirLoggingInterceptor implements Interceptor {
|
|||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Response intercept(@NotNull Interceptor.Chain chain) throws IOException {
|
||||
public Response intercept(@Nonnull Interceptor.Chain chain) throws IOException {
|
||||
// Log Request
|
||||
Request request = chain.request();
|
||||
logger.logRequest(request.method(), request.url().toString(), new ArrayList<>(request.headers().names()),
|
||||
|
|
|
@ -34,8 +34,8 @@ public class RetryInterceptor implements Interceptor {
|
|||
try {
|
||||
// If we are retrying a failed request that failed due to a bad response from the server, we must close it first
|
||||
if (response != null) {
|
||||
System.out.println("Previous " + chain.request().method() + " attempt returned HTTP<" + (response.code())
|
||||
+ "> from url -> " + chain.request().url() + ".");
|
||||
// System.out.println("Previous " + chain.request().method() + " attempt returned HTTP<" + (response.code())
|
||||
// + "> from url -> " + chain.request().url() + ".");
|
||||
response.close();
|
||||
}
|
||||
// System.out.println(chain.request().method() + " attempt <" + (retryCounter + 1) + "> to url -> " + chain.request().url());
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package org.hl7.fhir.r4.utils;
|
||||
package org.hl7.fhir.r4.utils.validation;
|
||||
|
||||
/*
|
||||
Copyright (c) 2011+, HL7, Inc.
|
||||
|
@ -29,18 +29,17 @@ package org.hl7.fhir.r4.utils;
|
|||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||
import org.hl7.fhir.r4.elementmodel.Element;
|
||||
import org.hl7.fhir.r4.elementmodel.Manager.FhirFormat;
|
||||
import org.hl7.fhir.r4.model.StructureDefinition;
|
||||
import org.hl7.fhir.r4.utils.ValidationProfileSet;
|
||||
import org.hl7.fhir.r4.utils.validation.constants.BestPracticeWarningLevel;
|
||||
import org.hl7.fhir.r4.utils.validation.constants.CheckDisplayOption;
|
||||
import org.hl7.fhir.r4.utils.validation.constants.IdStatus;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
@ -54,69 +53,21 @@ import com.google.gson.JsonObject;
|
|||
*/
|
||||
public interface IResourceValidator {
|
||||
|
||||
public enum ReferenceValidationPolicy {
|
||||
IGNORE, CHECK_TYPE_IF_EXISTS, CHECK_EXISTS, CHECK_EXISTS_AND_TYPE, CHECK_VALID;
|
||||
|
||||
public boolean checkExists() {
|
||||
return this == CHECK_EXISTS_AND_TYPE || this == CHECK_EXISTS || this == CHECK_VALID;
|
||||
}
|
||||
|
||||
public boolean checkType() {
|
||||
return this == CHECK_TYPE_IF_EXISTS || this == CHECK_EXISTS_AND_TYPE || this == CHECK_VALID;
|
||||
}
|
||||
|
||||
public boolean checkValid() {
|
||||
return this == CHECK_VALID;
|
||||
}
|
||||
}
|
||||
|
||||
public interface IValidatorResourceFetcher {
|
||||
Element fetch(Object appContext, String url) throws FHIRFormatError, DefinitionException, FHIRException, IOException;
|
||||
ReferenceValidationPolicy validationPolicy(Object appContext, String path, String url);
|
||||
boolean resolveURL(Object appContext, String path, String url) throws IOException, FHIRException;
|
||||
}
|
||||
|
||||
public enum BestPracticeWarningLevel {
|
||||
Ignore,
|
||||
Hint,
|
||||
Warning,
|
||||
Error
|
||||
}
|
||||
|
||||
public enum CheckDisplayOption {
|
||||
Ignore,
|
||||
Check,
|
||||
CheckCaseAndSpace,
|
||||
CheckCase,
|
||||
CheckSpace
|
||||
}
|
||||
|
||||
enum IdStatus {
|
||||
OPTIONAL, REQUIRED, PROHIBITED
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* how much to check displays for coded elements
|
||||
* @return
|
||||
*/
|
||||
CheckDisplayOption getCheckDisplay();
|
||||
void setCheckDisplay(CheckDisplayOption checkDisplay);
|
||||
|
||||
/**
|
||||
* whether the resource must have an id or not (depends on context)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
|
||||
IdStatus getResourceIdRule();
|
||||
void setResourceIdRule(IdStatus resourceIdRule);
|
||||
|
||||
/**
|
||||
* whether the validator should enforce best practice guidelines
|
||||
* as defined by various HL7 committees
|
||||
*
|
||||
*/
|
||||
BestPracticeWarningLevel getBestPracticeWarningLevel();
|
||||
IResourceValidator setBestPracticeWarningLevel(BestPracticeWarningLevel value);
|
||||
|
@ -124,27 +75,29 @@ public interface IResourceValidator {
|
|||
IValidatorResourceFetcher getFetcher();
|
||||
IResourceValidator setFetcher(IValidatorResourceFetcher value);
|
||||
|
||||
IValidationPolicyAdvisor getPolicyAdvisor();
|
||||
IResourceValidator setPolicyAdvisor(IValidationPolicyAdvisor advisor);
|
||||
|
||||
boolean isNoBindingMsgSuppressed();
|
||||
IResourceValidator setNoBindingMsgSuppressed(boolean noBindingMsgSuppressed);
|
||||
|
||||
public boolean isNoInvariantChecks();
|
||||
public IResourceValidator setNoInvariantChecks(boolean value) ;
|
||||
boolean isNoInvariantChecks();
|
||||
IResourceValidator setNoInvariantChecks(boolean value) ;
|
||||
|
||||
public boolean isNoTerminologyChecks();
|
||||
public IResourceValidator setNoTerminologyChecks(boolean noTerminologyChecks);
|
||||
boolean isNoTerminologyChecks();
|
||||
IResourceValidator setNoTerminologyChecks(boolean noTerminologyChecks);
|
||||
|
||||
public boolean isNoExtensibleWarnings();
|
||||
public IResourceValidator setNoExtensibleWarnings(boolean noExtensibleWarnings);
|
||||
boolean isNoExtensibleWarnings();
|
||||
IResourceValidator setNoExtensibleWarnings(boolean noExtensibleWarnings);
|
||||
|
||||
/**
|
||||
* Whether being unable to resolve a profile in found in Resource.meta.profile or ElementDefinition.type.profile or targetProfile is an error or just a warning
|
||||
* @return
|
||||
*/
|
||||
public boolean isErrorForUnknownProfiles();
|
||||
public void setErrorForUnknownProfiles(boolean errorForUnknownProfiles);
|
||||
boolean isErrorForUnknownProfiles();
|
||||
void setErrorForUnknownProfiles(boolean errorForUnknownProfiles);
|
||||
|
||||
public String getValidationLanguage();
|
||||
public void setValidationLanguage(String value);
|
||||
String getValidationLanguage();
|
||||
void setValidationLanguage(String value);
|
||||
|
||||
/**
|
||||
* Validate suite
|
||||
|
@ -194,5 +147,4 @@ public interface IResourceValidator {
|
|||
org.hl7.fhir.r4.elementmodel.Element validate(Object Context, List<ValidationMessage> errors, JsonObject object, String profile) throws FHIRException;
|
||||
org.hl7.fhir.r4.elementmodel.Element validate(Object Context, List<ValidationMessage> errors, JsonObject object, StructureDefinition profile) throws FHIRException;
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package org.hl7.fhir.r4.utils.validation;
|
||||
|
||||
import org.hl7.fhir.r4.elementmodel.Element;
|
||||
import org.hl7.fhir.r4.utils.validation.constants.ReferenceValidationPolicy;
|
||||
|
||||
public interface IValidationPolicyAdvisor {
|
||||
|
||||
ReferenceValidationPolicy policyForReference(IResourceValidator validator,
|
||||
Object appContext,
|
||||
String path,
|
||||
String url);
|
||||
|
||||
ReferenceValidationPolicy policyForContained(IResourceValidator validator,
|
||||
Object appContext,
|
||||
String containerType,
|
||||
String containerId,
|
||||
Element.SpecialElement containingResourceType,
|
||||
String path,
|
||||
String url);
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package org.hl7.fhir.r4.utils.validation;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r4.elementmodel.Element;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface IValidatorResourceFetcher {
|
||||
Element fetch(Object appContext, String url) throws FHIRException, IOException;
|
||||
boolean resolveURL(Object appContext, String path, String url) throws IOException, FHIRException;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package org.hl7.fhir.r4.utils.validation.constants;
|
||||
|
||||
public enum BestPracticeWarningLevel {
|
||||
Ignore,
|
||||
Hint,
|
||||
Warning,
|
||||
Error
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package org.hl7.fhir.r4.utils.validation.constants;
|
||||
|
||||
public enum CheckDisplayOption {
|
||||
Ignore,
|
||||
Check,
|
||||
CheckCaseAndSpace,
|
||||
CheckCase,
|
||||
CheckSpace
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package org.hl7.fhir.r4.utils.validation.constants;
|
||||
|
||||
public enum IdStatus {
|
||||
OPTIONAL,
|
||||
REQUIRED,
|
||||
PROHIBITED
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package org.hl7.fhir.r4.utils.validation.constants;
|
||||
|
||||
public enum ReferenceValidationPolicy {
|
||||
IGNORE,
|
||||
CHECK_TYPE_IF_EXISTS,
|
||||
CHECK_EXISTS,
|
||||
CHECK_EXISTS_AND_TYPE,
|
||||
CHECK_VALID;
|
||||
|
||||
public boolean checkExists() {
|
||||
return this == CHECK_EXISTS_AND_TYPE || this == CHECK_EXISTS || this == CHECK_VALID;
|
||||
}
|
||||
|
||||
public boolean checkType() {
|
||||
return this == CHECK_TYPE_IF_EXISTS || this == CHECK_EXISTS_AND_TYPE || this == CHECK_VALID;
|
||||
}
|
||||
|
||||
public boolean checkValid() {
|
||||
return this == CHECK_VALID;
|
||||
}
|
||||
}
|
|
@ -21,7 +21,7 @@ import java.io.*;
|
|||
public class ResourceRoundTripTests {
|
||||
|
||||
@BeforeAll
|
||||
public void setUp() throws Exception {
|
||||
public static void setUp() throws Exception {
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -22,7 +22,7 @@ import org.hl7.fhir.r4.model.ValueSet;
|
|||
import org.hl7.fhir.r4.test.utils.TestingUtilities;
|
||||
import org.hl7.fhir.r4.utils.FHIRPathEngine;
|
||||
import org.hl7.fhir.r4.utils.FHIRPathEngine.IEvaluationContext;
|
||||
import org.hl7.fhir.r4.utils.IResourceValidator;
|
||||
import org.hl7.fhir.r4.utils.validation.IResourceValidator;
|
||||
import org.hl7.fhir.r4.utils.NarrativeGenerator;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.core</artifactId>
|
||||
<version>5.5.12-SNAPSHOT</version>
|
||||
<version>5.6.16-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -691,8 +691,8 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
}
|
||||
if (!e.hasUserData(GENERATED_IN_SNAPSHOT)) {
|
||||
b.append(e.hasId() ? "id: "+e.getId() : "path: "+e.getPath());
|
||||
if (e.hasId()) {
|
||||
ce++;
|
||||
if (e.hasId()) {
|
||||
String msg = "No match found in the generated snapshot: check that the path and definitions are legal in the differential (including order)";
|
||||
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, url+"#"+e.getId(), msg, ValidationMessage.IssueSeverity.ERROR));
|
||||
}
|
||||
|
@ -2492,7 +2492,8 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
i = i + 1;
|
||||
} else {
|
||||
b.append("](");
|
||||
b.append(webUrl);
|
||||
// disabled 7-Dec 2021 GDG - we don't want to fool with relative URLs at all?
|
||||
// b.append(webUrl);
|
||||
i = i + 1;
|
||||
}
|
||||
} else
|
||||
|
@ -4773,7 +4774,7 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
|
||||
private void genFixedValue(HierarchicalTableGenerator gen, Row erow, DataType value, boolean snapshot, boolean pattern, String corePath, boolean skipnoValue) {
|
||||
String ref = pkp.getLinkFor(corePath, value.fhirType());
|
||||
if (ref != null) {
|
||||
if (ref != null && ref.contains(".html")) {
|
||||
ref = ref.substring(0, ref.indexOf(".html"))+"-definitions.html#";
|
||||
} else {
|
||||
ref = "?gen-fv?";
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package org.hl7.fhir.r5.conformance;
|
||||
|
||||
import org.hl7.fhir.r5.model.ElementDefinition;
|
||||
import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent;
|
||||
import org.hl7.fhir.r5.model.Resource;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
import org.hl7.fhir.utilities.VersionUtilities;
|
||||
|
||||
public class StructureDefinitionHacker {
|
||||
|
||||
private String version;
|
||||
|
||||
public StructureDefinitionHacker(String version) {
|
||||
super();
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public Resource fixSD(StructureDefinition sd) {
|
||||
if (VersionUtilities.isR4BVer(version) && sd.getUrl().equals("http://hl7.org/fhir/StructureDefinition/structuredefinition-fhir-type")) {
|
||||
// the definition of this one is wrong in R4B
|
||||
return fixR4BFhirType(sd);
|
||||
}
|
||||
return sd;
|
||||
}
|
||||
|
||||
private Resource fixR4BFhirType(StructureDefinition sd) {
|
||||
for (ElementDefinition ed : sd.getDifferential().getElement()) {
|
||||
if (ed.getPath().equals("Extension.value[x]")) {
|
||||
fixEDType(ed, "url", "uri");
|
||||
}
|
||||
}
|
||||
for (ElementDefinition ed : sd.getSnapshot().getElement()) {
|
||||
if (ed.getPath().equals("Extension.value[x]")) {
|
||||
fixEDType(ed, "url", "uri");
|
||||
}
|
||||
}
|
||||
return sd;
|
||||
}
|
||||
|
||||
private void fixEDType(ElementDefinition ed, String orig, String repl) {
|
||||
for (TypeRefComponent t : ed.getType()) {
|
||||
if (orig.equals(t.getCode())) {
|
||||
t.setCode(repl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -52,6 +52,7 @@ import org.hl7.fhir.exceptions.FHIRException;
|
|||
import org.hl7.fhir.exceptions.NoTerminologyServiceException;
|
||||
import org.hl7.fhir.exceptions.TerminologyServiceException;
|
||||
import org.hl7.fhir.r5.conformance.ProfileUtilities;
|
||||
import org.hl7.fhir.r5.context.BaseWorkerContext.ResourceProxy;
|
||||
import org.hl7.fhir.r5.context.CanonicalResourceManager.CanonicalResourceProxy;
|
||||
import org.hl7.fhir.r5.context.IWorkerContext.PackageVersion;
|
||||
import org.hl7.fhir.r5.context.IWorkerContext.ILoggingService.LogCategory;
|
||||
|
@ -110,6 +111,7 @@ import org.hl7.fhir.r5.terminologies.ValueSetExpander.TerminologyServiceErrorCla
|
|||
import org.hl7.fhir.r5.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
|
||||
import org.hl7.fhir.r5.terminologies.ValueSetExpanderSimple;
|
||||
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
||||
import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier;
|
||||
import org.hl7.fhir.utilities.OIDUtils;
|
||||
import org.hl7.fhir.utilities.TimeTracker;
|
||||
import org.hl7.fhir.utilities.ToolingClientLogger;
|
||||
|
@ -129,6 +131,35 @@ import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
|
|||
|
||||
public abstract class BaseWorkerContext extends I18nBase implements IWorkerContext{
|
||||
|
||||
public class ResourceProxy {
|
||||
private Resource resource;
|
||||
private CanonicalResourceProxy proxy;
|
||||
|
||||
public ResourceProxy(Resource resource) {
|
||||
super();
|
||||
this.resource = resource;
|
||||
}
|
||||
public ResourceProxy(CanonicalResourceProxy proxy) {
|
||||
super();
|
||||
this.proxy = proxy;
|
||||
}
|
||||
|
||||
public Resource getResource() {
|
||||
return resource != null ? resource : proxy.getResource();
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
if (resource == null) {
|
||||
return proxy.getUrl();
|
||||
} else if (resource instanceof CanonicalResource) {
|
||||
return ((CanonicalResource) resource).getUrl();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class MetadataResourceVersionComparator<T extends CanonicalResource> implements Comparator<T> {
|
||||
|
||||
private List<T> list;
|
||||
|
@ -165,7 +196,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
private boolean isTxCaching;
|
||||
private Set<String> cached = new HashSet<>();
|
||||
|
||||
private Map<String, Map<String, Resource>> allResourcesById = new HashMap<String, Map<String, Resource>>();
|
||||
private Map<String, Map<String, ResourceProxy>> allResourcesById = new HashMap<String, Map<String, ResourceProxy>>();
|
||||
// all maps are to the full URI
|
||||
private CanonicalResourceManager<CodeSystem> codeSystems = new CanonicalResourceManager<CodeSystem>(false);
|
||||
private Set<String> supportedCodeSystems = new HashSet<String>();
|
||||
|
@ -276,6 +307,12 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
|
||||
public void registerResourceFromPackage(CanonicalResourceProxy r, PackageVersion packageInfo) throws FHIRException {
|
||||
synchronized (lock) {
|
||||
Map<String, ResourceProxy> map = allResourcesById.get(r.getType());
|
||||
if (map == null) {
|
||||
map = new HashMap<String, ResourceProxy>();
|
||||
allResourcesById.put(r.getType(), map);
|
||||
}
|
||||
map.put(r.getId(), new ResourceProxy(r));
|
||||
|
||||
String url = r.getUrl();
|
||||
if (!allowLoadingDuplicates && hasResource(r.getType(), url)) {
|
||||
|
@ -338,12 +375,14 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
|
||||
public void cacheResourceFromPackage(Resource r, PackageVersion packageInfo) throws FHIRException {
|
||||
synchronized (lock) {
|
||||
Map<String, Resource> map = allResourcesById.get(r.fhirType());
|
||||
Map<String, ResourceProxy> map = allResourcesById.get(r.fhirType());
|
||||
if (map == null) {
|
||||
map = new HashMap<String, Resource>();
|
||||
map = new HashMap<String, ResourceProxy>();
|
||||
allResourcesById.put(r.fhirType(), map);
|
||||
}
|
||||
map.put(r.getId(), r);
|
||||
if ((packageInfo == null || !packageInfo.isExamplesPackage()) || !map.containsKey(r.getId())) {
|
||||
map.put(r.getId(), new ResourceProxy(r));
|
||||
}
|
||||
|
||||
if (r instanceof CodeSystem || r instanceof NamingSystem) {
|
||||
oidCache.clear();
|
||||
|
@ -498,6 +537,14 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(String system) {
|
||||
if (system == null) {
|
||||
return null;
|
||||
}
|
||||
if (system.contains("|")) {
|
||||
String s = system.substring(0, system.indexOf("|"));
|
||||
String v = system.substring(system.indexOf("|")+1);
|
||||
return fetchCodeSystem(s, v);
|
||||
}
|
||||
CodeSystem cs;
|
||||
synchronized (lock) {
|
||||
cs = codeSystems.get(system);
|
||||
|
@ -511,6 +558,23 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
return cs;
|
||||
}
|
||||
|
||||
public CodeSystem fetchCodeSystem(String system, String version) {
|
||||
if (version == null) {
|
||||
return fetchCodeSystem(system);
|
||||
}
|
||||
CodeSystem cs;
|
||||
synchronized (lock) {
|
||||
cs = codeSystems.get(system, version);
|
||||
}
|
||||
if (cs == null && locator != null) {
|
||||
locator.findResource(this, system);
|
||||
synchronized (lock) {
|
||||
cs = codeSystems.get(system);
|
||||
}
|
||||
}
|
||||
return cs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsSystem(String system) throws TerminologyServiceException {
|
||||
synchronized (lock) {
|
||||
|
@ -643,10 +707,18 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
if (expParameters == null)
|
||||
throw new Error(formatMessage(I18nConstants.NO_EXPANSION_PARAMETERS_PROVIDED));
|
||||
Parameters p = expParameters.copy();
|
||||
return expandVS(vs, cacheOk, heirarchical, p);
|
||||
return expandVS(vs, cacheOk, heirarchical, false, p);
|
||||
}
|
||||
|
||||
public ValueSetExpansionOutcome expandVS(ValueSet vs, boolean cacheOk, boolean heirarchical, Parameters p) {
|
||||
@Override
|
||||
public ValueSetExpansionOutcome expandVS(ValueSet vs, boolean cacheOk, boolean heirarchical, boolean incompleteOk) {
|
||||
if (expParameters == null)
|
||||
throw new Error(formatMessage(I18nConstants.NO_EXPANSION_PARAMETERS_PROVIDED));
|
||||
Parameters p = expParameters.copy();
|
||||
return expandVS(vs, cacheOk, heirarchical, incompleteOk, p);
|
||||
}
|
||||
|
||||
public ValueSetExpansionOutcome expandVS(ValueSet vs, boolean cacheOk, boolean heirarchical, boolean incompleteOk, Parameters p) {
|
||||
if (p == null) {
|
||||
throw new Error(formatMessage(I18nConstants.NO_PARAMETERS_PROVIDED_TO_EXPANDVS));
|
||||
}
|
||||
|
@ -673,6 +745,9 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
}
|
||||
p.setParameter("includeDefinition", false);
|
||||
p.setParameter("excludeNested", !heirarchical);
|
||||
if (incompleteOk) {
|
||||
p.setParameter("incomplete-ok", true);
|
||||
}
|
||||
|
||||
List<String> allErrors = new ArrayList<>();
|
||||
|
||||
|
@ -853,6 +928,12 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
|
||||
@Override
|
||||
public ValidationResult validateCode(ValidationOptions options, Coding code, ValueSet vs) {
|
||||
ValidationContextCarrier ctxt = new ValidationContextCarrier();
|
||||
return validateCode(options, code, vs, ctxt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult validateCode(ValidationOptions options, Coding code, ValueSet vs, ValidationContextCarrier ctxt) {
|
||||
if (options == null) {
|
||||
options = ValidationOptions.defaults();
|
||||
}
|
||||
|
@ -872,7 +953,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
if (options.isUseClient()) {
|
||||
// ok, first we try to validate locally
|
||||
try {
|
||||
ValueSetCheckerSimple vsc = new ValueSetCheckerSimple(options, vs, this);
|
||||
ValueSetCheckerSimple vsc = new ValueSetCheckerSimple(options, vs, this, ctxt);
|
||||
if (!vsc.isServerSide(code.getSystem())) {
|
||||
res = vsc.validateCode(code);
|
||||
if (txCache != null) {
|
||||
|
@ -992,14 +1073,16 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
}
|
||||
}
|
||||
if (vs != null) {
|
||||
if (isTxCaching && cacheId != null && cached.contains(vs.getUrl()+"|"+vs.getVersion())) {
|
||||
if (isTxCaching && cacheId != null && vs.getUrl() != null && cached.contains(vs.getUrl()+"|"+vs.getVersion())) {
|
||||
pin.addParameter().setName("url").setValue(new UriType(vs.getUrl()+(vs.hasVersion() ? "|"+vs.getVersion() : "")));
|
||||
} else if (options.getVsAsUrl()){
|
||||
pin.addParameter().setName("url").setValue(new StringType(vs.getUrl()));
|
||||
} else {
|
||||
pin.addParameter().setName("valueSet").setResource(vs);
|
||||
if (vs.getUrl() != null) {
|
||||
cached.add(vs.getUrl()+"|"+vs.getVersion());
|
||||
}
|
||||
}
|
||||
cache = true;
|
||||
addDependentResources(pin, vs);
|
||||
}
|
||||
|
@ -1205,8 +1288,12 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
return fetchResourceWithException(cls, uri, null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Resource> T fetchResourceWithException(Class<T> class_, String uri, CanonicalResource source) throws FHIRException {
|
||||
return fetchResourceWithException(class_, uri, null, source);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Resource> T fetchResourceWithException(Class<T> class_, String uri, String version, CanonicalResource source) throws FHIRException {
|
||||
if (uri == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -1216,7 +1303,6 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
}
|
||||
synchronized (lock) {
|
||||
|
||||
String version = null;
|
||||
if (uri.contains("|")) {
|
||||
version = uri.substring(uri.lastIndexOf("|")+1);
|
||||
uri = uri.substring(0, uri.lastIndexOf("|"));
|
||||
|
@ -1264,12 +1350,22 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
if (questionnaires.has(uri)) {
|
||||
return (T) questionnaires.get(uri, version);
|
||||
}
|
||||
for (Map<String, Resource> rt : allResourcesById.values()) {
|
||||
for (Resource r : rt.values()) {
|
||||
if (r instanceof CanonicalResource) {
|
||||
CanonicalResource mr = (CanonicalResource) r;
|
||||
if (uri.equals(mr.getUrl())) {
|
||||
return (T) mr;
|
||||
if (uri.matches(Constants.URI_REGEX) && !uri.contains("ValueSet")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// it might be a special URL.
|
||||
if (Utilities.isAbsoluteUrl(uri) || uri.startsWith("ValueSet/")) {
|
||||
Resource res = null; // findTxValueSet(uri);
|
||||
if (res != null) {
|
||||
return (T) res;
|
||||
}
|
||||
}
|
||||
for (Map<String, ResourceProxy> rt : allResourcesById.values()) {
|
||||
for (ResourceProxy r : rt.values()) {
|
||||
if (uri.equals(r.getUrl())) {
|
||||
if (version == null || version == r.getResource().getMeta().getVersionId()) {
|
||||
return (T) r.getResource();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1314,20 +1410,6 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
if (class_ == Questionnaire.class) {
|
||||
return (T) questionnaires.get(uri, version);
|
||||
}
|
||||
if (class_ == null) {
|
||||
if (uri.matches(Constants.URI_REGEX) && !uri.contains("ValueSet")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// it might be a special URL.
|
||||
if (Utilities.isAbsoluteUrl(uri) || uri.startsWith("ValueSet/")) {
|
||||
Resource res = null; // findTxValueSet(uri);
|
||||
if (res != null) {
|
||||
return (T) res;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (supportedCodeSystems.contains(uri)) {
|
||||
return null;
|
||||
}
|
||||
|
@ -1453,13 +1535,10 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
if (questionnaires.has(uri)) {
|
||||
return (T) questionnaires.get(uri, version);
|
||||
}
|
||||
for (Map<String, Resource> rt : allResourcesById.values()) {
|
||||
for (Resource r : rt.values()) {
|
||||
if (r instanceof CanonicalResource) {
|
||||
CanonicalResource mr = (CanonicalResource) r;
|
||||
if (uri.equals(mr.getUrl())) {
|
||||
return (T) mr;
|
||||
}
|
||||
for (Map<String, ResourceProxy> rt : allResourcesById.values()) {
|
||||
for (ResourceProxy r : rt.values()) {
|
||||
if (uri.equals(r.getUrl())) {
|
||||
return (T) r.getResource();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1533,7 +1612,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
String[] parts = uri.split("\\/");
|
||||
if (!Utilities.noString(type) && parts.length == 1) {
|
||||
if (allResourcesById.containsKey(type)) {
|
||||
return allResourcesById.get(type).get(parts[0]);
|
||||
return allResourcesById.get(type).get(parts[0]).getResource();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
@ -1544,7 +1623,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
throw new Error(formatMessage(I18nConstants.RESOURCE_TYPE_MISMATCH_FOR___, type, uri));
|
||||
}
|
||||
}
|
||||
return allResourcesById.get(parts[parts.length-2]).get(parts[parts.length-1]);
|
||||
return allResourcesById.get(parts[parts.length-2]).get(parts[parts.length-1]).getResource();
|
||||
} else {
|
||||
throw new Error(formatMessage(I18nConstants.UNABLE_TO_PROCESS_REQUEST_FOR_RESOURCE_FOR___, type, uri));
|
||||
}
|
||||
|
@ -1567,6 +1646,14 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
}
|
||||
}
|
||||
|
||||
public <T extends Resource> T fetchResource(Class<T> class_, String uri, String version) {
|
||||
try {
|
||||
return fetchResourceWithException(class_, uri, version, null);
|
||||
} catch (FHIRException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Resource> boolean hasResource(Class<T> class_, String uri) {
|
||||
try {
|
||||
|
@ -1656,13 +1743,13 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
public void dropResource(String fhirType, String id) {
|
||||
synchronized (lock) {
|
||||
|
||||
Map<String, Resource> map = allResourcesById.get(fhirType);
|
||||
Map<String, ResourceProxy> map = allResourcesById.get(fhirType);
|
||||
if (map == null) {
|
||||
map = new HashMap<String, Resource>();
|
||||
map = new HashMap<String, ResourceProxy>();
|
||||
allResourcesById.put(fhirType, map);
|
||||
}
|
||||
if (map.containsKey(id)) {
|
||||
map.remove(id);
|
||||
map.remove(id); // this is a challenge because we might have more than one resource with this id (different versions)
|
||||
}
|
||||
|
||||
if (fhirType.equals("StructureDefinition")) {
|
||||
|
|
|
@ -236,6 +236,9 @@ public class CanonicalResourceManager<T extends CanonicalResource> {
|
|||
}
|
||||
}
|
||||
CachedCanonicalResource<T> existing = cr.hasVersion() ? map.get(cr.getUrl()+"|"+cr.getVersion()) : map.get(cr.getUrl()+"|#0");
|
||||
if (existing != null && (cr.getPackageInfo() != null && cr.getPackageInfo().isExamplesPackage())) {
|
||||
return;
|
||||
}
|
||||
if (existing != null) {
|
||||
list.remove(existing);
|
||||
}
|
||||
|
|
|
@ -89,12 +89,13 @@ public class HTMLClientLogger extends BaseLogger implements ToolingClientLogger
|
|||
if (DEBUG) {
|
||||
System.out.println(" txlog resp: " +outcome+" "+present(body));
|
||||
}
|
||||
req = false;
|
||||
|
||||
if (file == null)
|
||||
return;
|
||||
if (!req) {
|
||||
System.out.println("Record Response without request");
|
||||
}
|
||||
req = false;
|
||||
file.println("<pre>");
|
||||
file.println(outcome);
|
||||
for (String s : headers)
|
||||
|
|
|
@ -44,8 +44,8 @@ import org.fhir.ucum.UcumService;
|
|||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.TerminologyServiceException;
|
||||
import org.hl7.fhir.r5.context.IWorkerContext.CodingValidationRequest;
|
||||
import org.hl7.fhir.r5.context.TerminologyCache.CacheToken;
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
import org.hl7.fhir.r5.formats.IParser;
|
||||
import org.hl7.fhir.r5.formats.ParserType;
|
||||
import org.hl7.fhir.r5.model.Bundle;
|
||||
|
@ -64,12 +64,14 @@ import org.hl7.fhir.r5.model.ValueSet;
|
|||
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.r5.terminologies.ValueSetExpander.TerminologyServiceErrorClass;
|
||||
import org.hl7.fhir.r5.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
|
||||
import org.hl7.fhir.r5.utils.IResourceValidator;
|
||||
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
|
||||
import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier;
|
||||
import org.hl7.fhir.utilities.TimeTracker;
|
||||
import org.hl7.fhir.utilities.TranslationServices;
|
||||
import org.hl7.fhir.utilities.npm.BasePackageCacheManager;
|
||||
import org.hl7.fhir.utilities.npm.NpmPackage;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
import org.hl7.fhir.utilities.validation.ValidationOptions;
|
||||
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
@ -168,6 +170,9 @@ public interface IWorkerContext {
|
|||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
public boolean isExamplesPackage() {
|
||||
return !(id.startsWith("hl7.fhir.") && id.endsWith(".example"));
|
||||
}
|
||||
}
|
||||
|
||||
public class PackageDetails extends PackageVersion {
|
||||
|
@ -191,13 +196,14 @@ public interface IWorkerContext {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
public interface ICanonicalResourceLocator {
|
||||
void findResource(Object caller, String url); // if it can be found, put it in the context
|
||||
}
|
||||
|
||||
public interface IContextResourceLoader {
|
||||
/**
|
||||
* @return List of the resource types that shoud be loaded
|
||||
* @return List of the resource types that should be loaded
|
||||
*/
|
||||
String[] getTypes();
|
||||
|
||||
|
@ -242,7 +248,6 @@ public interface IWorkerContext {
|
|||
IContextResourceLoader getNewLoader(NpmPackage npm) throws JsonSyntaxException, IOException;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the versions of the definitions loaded in context
|
||||
* @return
|
||||
|
@ -335,6 +340,7 @@ public interface IWorkerContext {
|
|||
*/
|
||||
public <T extends Resource> T fetchResource(Class<T> class_, String uri);
|
||||
public <T extends Resource> T fetchResourceWithException(Class<T> class_, String uri) throws FHIRException;
|
||||
public <T extends Resource> T fetchResource(Class<T> class_, String uri, String version);
|
||||
|
||||
/** has the same functionality as fetchResource, but passes in information about the source of the
|
||||
* reference (this may affect resolution of version)
|
||||
|
@ -476,6 +482,7 @@ public interface IWorkerContext {
|
|||
* @return
|
||||
*/
|
||||
public CodeSystem fetchCodeSystem(String system);
|
||||
public CodeSystem fetchCodeSystem(String system, String version);
|
||||
|
||||
/**
|
||||
* True if the underlying terminology service provider will do
|
||||
|
@ -508,6 +515,14 @@ public interface IWorkerContext {
|
|||
*/
|
||||
public ValueSetExpansionOutcome expandVS(ValueSet source, boolean cacheOk, boolean heiarchical);
|
||||
|
||||
/**
|
||||
* ValueSet Expansion - see $expand
|
||||
*
|
||||
* @param source
|
||||
* @return
|
||||
*/
|
||||
public ValueSetExpansionOutcome expandVS(ValueSet source, boolean cacheOk, boolean heiarchical, boolean incompleteOk);
|
||||
|
||||
/**
|
||||
* ValueSet Expansion - see $expand, but resolves the binding first
|
||||
*
|
||||
|
@ -734,6 +749,8 @@ public interface IWorkerContext {
|
|||
*/
|
||||
public ValidationResult validateCode(ValidationOptions options, Coding code, ValueSet vs);
|
||||
|
||||
public ValidationResult validateCode(ValidationOptions options, Coding code, ValueSet vs, ValidationContextCarrier ctxt);
|
||||
|
||||
public void validateCodeBatch(ValidationOptions options, List<? extends CodingValidationRequest> codes, ValueSet vs);
|
||||
|
||||
/**
|
||||
|
|
|
@ -54,9 +54,7 @@ import org.hl7.fhir.exceptions.FHIRFormatError;
|
|||
import org.hl7.fhir.r5.conformance.ProfileUtilities;
|
||||
import org.hl7.fhir.r5.conformance.ProfileUtilities.ProfileKnowledgeProvider;
|
||||
import org.hl7.fhir.r5.context.CanonicalResourceManager.CanonicalResourceProxy;
|
||||
import org.hl7.fhir.r5.context.IWorkerContext.PackageVersion;
|
||||
import org.hl7.fhir.r5.context.IWorkerContext.ILoggingService.LogCategory;
|
||||
import org.hl7.fhir.r5.context.SimpleWorkerContext.PackageResourceLoader;
|
||||
import org.hl7.fhir.r5.formats.IParser;
|
||||
import org.hl7.fhir.r5.formats.JsonParser;
|
||||
import org.hl7.fhir.r5.formats.ParserType;
|
||||
|
@ -76,7 +74,7 @@ import org.hl7.fhir.r5.model.StructureMap;
|
|||
import org.hl7.fhir.r5.model.StructureMap.StructureMapModelMode;
|
||||
import org.hl7.fhir.r5.model.StructureMap.StructureMapStructureComponent;
|
||||
import org.hl7.fhir.r5.terminologies.TerminologyClient;
|
||||
import org.hl7.fhir.r5.utils.IResourceValidator;
|
||||
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
|
||||
import org.hl7.fhir.r5.utils.XVerExtensionManager;
|
||||
import org.hl7.fhir.utilities.CSFileInputStream;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
|
@ -85,15 +83,12 @@ import org.hl7.fhir.utilities.Utilities;
|
|||
import org.hl7.fhir.utilities.VersionUtilities;
|
||||
import org.hl7.fhir.utilities.i18n.I18nConstants;
|
||||
import org.hl7.fhir.utilities.npm.BasePackageCacheManager;
|
||||
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
|
||||
import org.hl7.fhir.utilities.npm.NpmPackage;
|
||||
import org.hl7.fhir.utilities.npm.NpmPackage.PackageResourceInformation;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
|
||||
/*
|
||||
|
|
|
@ -118,12 +118,14 @@ public abstract class ParserBase {
|
|||
|
||||
//FIXME: i18n should be done here
|
||||
public void logError(int line, int col, String path, IssueType type, String message, IssueSeverity level) throws FHIRFormatError {
|
||||
if (errors != null) {
|
||||
if (policy == ValidationPolicy.EVERYTHING) {
|
||||
ValidationMessage msg = new ValidationMessage(Source.InstanceValidator, type, line, col, path, message, level);
|
||||
errors.add(msg);
|
||||
} else if (level == IssueSeverity.FATAL || (level == IssueSeverity.ERROR && policy == ValidationPolicy.QUICK))
|
||||
throw new FHIRFormatError(message+String.format(" at line %d col %d", line, col));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected StructureDefinition getDefinition(int line, int col, String ns, String name) throws FHIRFormatError {
|
||||
|
|
|
@ -237,6 +237,7 @@ public class SHCParser extends ParserBase {
|
|||
|
||||
private static final int BUFFER_SIZE = 1024;
|
||||
public static final String CURRENT_PACKAGE = "hl7.fhir.uv.shc-vaccination#0.6.2";
|
||||
private static final int MAX_ALLOWED_SHC_LENGTH = 1195;
|
||||
|
||||
// todo: deal with chunking
|
||||
public static String decodeQRCode(String src) {
|
||||
|
@ -253,10 +254,14 @@ public class SHCParser extends ParserBase {
|
|||
return b.toString();
|
||||
}
|
||||
|
||||
public static JWT decodeJWT(String jwt) throws IOException, DataFormatException {
|
||||
public JWT decodeJWT(String jwt) throws IOException, DataFormatException {
|
||||
if (jwt.startsWith("shc:/")) {
|
||||
jwt = decodeQRCode(jwt);
|
||||
}
|
||||
if (jwt.length() > MAX_ALLOWED_SHC_LENGTH) {
|
||||
logError(-1, -1, "jwt", IssueType.TOOLONG, "JWT Payload limit length is "+MAX_ALLOWED_SHC_LENGTH+" bytes for a single image - this has "+jwt.length()+" bytes", IssueSeverity.ERROR);
|
||||
}
|
||||
|
||||
String[] parts = splitToken(jwt);
|
||||
byte[] headerJson;
|
||||
byte[] payloadJson;
|
||||
|
|
|
@ -554,6 +554,10 @@ public abstract class CanonicalResource extends DomainResource {
|
|||
return true;
|
||||
}
|
||||
|
||||
public String getVersionedUrl() {
|
||||
return hasVersion() ? getUrl()+"|"+getVersion() : getUrl();
|
||||
}
|
||||
|
||||
// end addition
|
||||
|
||||
}
|
||||
|
|
|
@ -6716,6 +6716,10 @@ The MedicationUsage resource was previously called MedicationStatement.
|
|||
* R5 Preview #1.
|
||||
*/
|
||||
_4_2_0,
|
||||
/**
|
||||
* R4B
|
||||
*/
|
||||
_4_3_0_CIBUILD,
|
||||
/**
|
||||
* R5 Preview #2.
|
||||
*/
|
||||
|
@ -6733,8 +6737,6 @@ The MedicationUsage resource was previously called MedicationStatement.
|
|||
*/
|
||||
NULL;
|
||||
|
||||
public static final FHIRVersion R4B = FHIRVersion._4_1_0;
|
||||
|
||||
public static FHIRVersion fromCode(String codeString) throws FHIRException {
|
||||
if (codeString == null || "".equals(codeString))
|
||||
return null;
|
||||
|
@ -6788,6 +6790,8 @@ The MedicationUsage resource was previously called MedicationStatement.
|
|||
return _4_1_0;
|
||||
if ("4.2.0".equals(codeString))
|
||||
return _4_2_0;
|
||||
if ("4.3.0-CIBUILD".equals(codeString))
|
||||
return _4_3_0_CIBUILD;
|
||||
if ("4.4.0".equals(codeString))
|
||||
return _4_4_0;
|
||||
if ("4.5.0".equals(codeString))
|
||||
|
@ -6823,6 +6827,7 @@ The MedicationUsage resource was previously called MedicationStatement.
|
|||
case _4_0_1: return "4.0.1";
|
||||
case _4_1_0: return "4.1.0";
|
||||
case _4_2_0: return "4.2.0";
|
||||
case _4_3_0_CIBUILD: return "4.3.0-CIBUILD";
|
||||
case _4_4_0: return "4.4.0";
|
||||
case _4_5_0: return "4.5.0";
|
||||
case _4_6_0: return "4.6.0";
|
||||
|
@ -6857,6 +6862,7 @@ The MedicationUsage resource was previously called MedicationStatement.
|
|||
case _4_0_1: return "http://hl7.org/fhir/FHIR-version";
|
||||
case _4_1_0: return "http://hl7.org/fhir/FHIR-version";
|
||||
case _4_2_0: return "http://hl7.org/fhir/FHIR-version";
|
||||
case _4_3_0_CIBUILD: return "http://hl7.org/fhir/FHIR-version";
|
||||
case _4_4_0: return "http://hl7.org/fhir/FHIR-version";
|
||||
case _4_5_0: return "http://hl7.org/fhir/FHIR-version";
|
||||
case _4_6_0: return "http://hl7.org/fhir/FHIR-version";
|
||||
|
@ -6891,6 +6897,7 @@ The MedicationUsage resource was previously called MedicationStatement.
|
|||
case _4_0_1: return "FHIR Release 4 (Normative + STU) with 1 technical errata.";
|
||||
case _4_1_0: return "Interim Version.";
|
||||
case _4_2_0: return "R5 Preview #1.";
|
||||
case _4_3_0_CIBUILD: return "R4B CIBuild";
|
||||
case _4_4_0: return "R5 Preview #2.";
|
||||
case _4_5_0: return "R5 Preview #3.";
|
||||
case _4_6_0: return "R5 Draft Ballot.";
|
||||
|
@ -6925,6 +6932,7 @@ The MedicationUsage resource was previously called MedicationStatement.
|
|||
case _4_0_1: return "4.0.1";
|
||||
case _4_1_0: return "4.1.0";
|
||||
case _4_2_0: return "4.2.0";
|
||||
case _4_3_0_CIBUILD: return "4.3.0-CIBUILD";
|
||||
case _4_4_0: return "4.4.0";
|
||||
case _4_5_0: return "4.5.0";
|
||||
case _4_6_0: return "4.6.0";
|
||||
|
@ -6988,6 +6996,8 @@ public String toCode(int len) {
|
|||
return true;
|
||||
if ("4.2.0".equals(codeString))
|
||||
return true;
|
||||
if ("4.3.0-CIBUILD".equals(codeString))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -6998,7 +7008,7 @@ public String toCode(int len) {
|
|||
|
||||
|
||||
public boolean isR4B() {
|
||||
return toCode().startsWith("4.1");
|
||||
return toCode().startsWith("4.1") || toCode().startsWith("4.3");
|
||||
}
|
||||
|
||||
// end addition
|
||||
|
@ -7059,6 +7069,8 @@ public String toCode(int len) {
|
|||
return FHIRVersion._4_1_0;
|
||||
if ("4.2.0".equals(codeString))
|
||||
return FHIRVersion._4_2_0;
|
||||
if ("4.3.0-CIBUILD".equals(codeString))
|
||||
return FHIRVersion._4_3_0_CIBUILD;
|
||||
if ("4.4.0".equals(codeString))
|
||||
return FHIRVersion._4_4_0;
|
||||
if ("4.5.0".equals(codeString))
|
||||
|
@ -7125,6 +7137,8 @@ public String toCode(int len) {
|
|||
return new Enumeration<FHIRVersion>(this, FHIRVersion._4_1_0);
|
||||
if ("4.2.0".equals(codeString))
|
||||
return new Enumeration<FHIRVersion>(this, FHIRVersion._4_2_0);
|
||||
if ("4.3.0-CIBUILD".equals(codeString))
|
||||
return new Enumeration<FHIRVersion>(this, FHIRVersion._4_3_0_CIBUILD);
|
||||
if ("4.4.0".equals(codeString))
|
||||
return new Enumeration<FHIRVersion>(this, FHIRVersion._4_4_0);
|
||||
if ("4.5.0".equals(codeString))
|
||||
|
@ -7184,6 +7198,8 @@ public String toCode(int len) {
|
|||
return "4.1.0";
|
||||
if (code == FHIRVersion._4_2_0)
|
||||
return "4.2.0";
|
||||
if (code == FHIRVersion._4_3_0_CIBUILD)
|
||||
return "4.3.0-CIBUILD";
|
||||
if (code == FHIRVersion._4_4_0)
|
||||
return "4.4.0";
|
||||
if (code == FHIRVersion._4_5_0)
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.hl7.fhir.r5.model.CapabilityStatement.ResourceInteractionComponent;
|
|||
import org.hl7.fhir.r5.model.CapabilityStatement.SystemInteractionComponent;
|
||||
import org.hl7.fhir.r5.model.CapabilityStatement.SystemRestfulInteraction;
|
||||
import org.hl7.fhir.r5.model.CapabilityStatement.TypeRestfulInteraction;
|
||||
import org.hl7.fhir.r5.model.CanonicalType;
|
||||
import org.hl7.fhir.r5.renderers.utils.RenderingContext;
|
||||
import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper;
|
||||
import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext;
|
||||
|
@ -79,12 +80,41 @@ public class CapabilityStatementRenderer extends ResourceRenderer {
|
|||
if (hasHistory)
|
||||
tr.th().b().attribute("title", "GET changes for all resources of the type (history interaction on type)").tx("History");
|
||||
|
||||
XhtmlNode profCell = null;
|
||||
boolean hasProf = false;
|
||||
boolean hasSupProf = false;
|
||||
for (CapabilityStatementRestResourceComponent r : rest.getResource()) {
|
||||
tr = t.tr();
|
||||
tr.td().addText(r.getType());
|
||||
if (r.hasProfile()) {
|
||||
tr.td().ah(r.getProfile()).addText(r.getProfile());
|
||||
|
||||
//Show profiles
|
||||
profCell = tr.td();
|
||||
hasProf = r.hasProfile();
|
||||
hasSupProf = r.hasSupportedProfile();
|
||||
if ((!hasProf) && (!hasSupProf)) {
|
||||
profCell.nbsp();
|
||||
}
|
||||
else if (hasProf) {
|
||||
profCell.ah(r.getProfile()).addText(r.getProfile());
|
||||
if (hasSupProf) {
|
||||
profCell.br();
|
||||
profCell.addText("Additional supported profiles:");
|
||||
for (CanonicalType sp: r.getSupportedProfile()) {
|
||||
profCell.br();
|
||||
profCell.nbsp().nbsp();
|
||||
profCell.ah(sp.getValue()).addText(sp.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
else { //Case of only supported profiles
|
||||
profCell.addText("Supported profiles:");
|
||||
for (CanonicalType sp: r.getSupportedProfile()) {
|
||||
profCell.br();
|
||||
profCell.nbsp().nbsp();
|
||||
profCell.ah(sp.getValue()).addText(sp.getValue());
|
||||
}
|
||||
}
|
||||
//Show capabilities
|
||||
tr.td().addText(showOp(r, TypeRestfulInteraction.READ));
|
||||
if (hasVRead)
|
||||
tr.td().addText(showOp(r, TypeRestfulInteraction.VREAD));
|
||||
|
|
|
@ -94,8 +94,10 @@ public class CodeSystemRenderer extends TerminologyRenderer {
|
|||
private void generateProperties(XhtmlNode x, CodeSystem cs) {
|
||||
if (cs.hasProperty()) {
|
||||
boolean hasRendered = false;
|
||||
boolean hasURI = false;
|
||||
for (PropertyComponent p : cs.getProperty()) {
|
||||
hasRendered = hasRendered || !p.getCode().equals(ToolingExtensions.getPresentation(p, p.getCodeElement()));
|
||||
hasURI = hasURI || p.hasUri();
|
||||
}
|
||||
|
||||
x.para().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Properties", getContext().getLang()));
|
||||
|
@ -105,18 +107,22 @@ public class CodeSystemRenderer extends TerminologyRenderer {
|
|||
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Name", getContext().getLang()));
|
||||
}
|
||||
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Code", getContext().getLang()));
|
||||
if (hasURI) {
|
||||
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "URL", getContext().getLang()));
|
||||
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Description", getContext().getLang()));
|
||||
}
|
||||
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Type", getContext().getLang()));
|
||||
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Description", getContext().getLang()));
|
||||
for (PropertyComponent p : cs.getProperty()) {
|
||||
tr = tbl.tr();
|
||||
if (hasRendered) {
|
||||
tr.td().tx(ToolingExtensions.getPresentation(p, p.getCodeElement()));
|
||||
}
|
||||
tr.td().tx(p.getCode());
|
||||
if (hasURI) {
|
||||
tr.td().tx(p.getUri());
|
||||
tr.td().tx(p.getDescription());
|
||||
}
|
||||
tr.td().tx(p.hasType() ? p.getType().toCode() : "");
|
||||
tr.td().tx(p.getDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -126,7 +132,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
|
|||
if (cs.getContent() == CodeSystemContentMode.COMPLETE)
|
||||
p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), "This code system %s defines the following codes", cs.getUrl())+":");
|
||||
else if (cs.getContent() == CodeSystemContentMode.EXAMPLE)
|
||||
p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), "This code system %s defines many codes, of which the following are some examples", cs.getUrl())+":");
|
||||
p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), "This code system %s defines some example codes", cs.getUrl())+":");
|
||||
else if (cs.getContent() == CodeSystemContentMode.FRAGMENT )
|
||||
p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), "This code system %s defines many codes, of which the following are a subset", cs.getUrl())+":");
|
||||
else if (cs.getContent() == CodeSystemContentMode.NOTPRESENT ) {
|
||||
|
@ -141,6 +147,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
|
|||
boolean hierarchy = false;
|
||||
boolean version = false;
|
||||
boolean ignoreStatus = false;
|
||||
boolean isSupplement = cs.getContent() == CodeSystemContentMode.SUPPLEMENT;
|
||||
List<PropertyComponent> properties = new ArrayList<>();
|
||||
for (PropertyComponent cp : cs.getProperty()) {
|
||||
if (showPropertyInTable(cp)) {
|
||||
|
@ -170,7 +177,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
|
|||
List<String> langs = new ArrayList<>();
|
||||
addMapHeaders(addTableHeaderRowStandard(t, hierarchy, display, definitions, commentS, version, deprecated, properties, null, false), maps);
|
||||
for (ConceptDefinitionComponent c : csNav.getConcepts(null)) {
|
||||
hasExtensions = addDefineRowToTable(t, c, 0, hierarchy, display, definitions, commentS, version, deprecated, maps, cs.getUrl(), cs, properties, csNav, langs) || hasExtensions;
|
||||
hasExtensions = addDefineRowToTable(t, c, 0, hierarchy, display, definitions, commentS, version, deprecated, maps, cs.getUrl(), cs, properties, csNav, langs, isSupplement) || hasExtensions;
|
||||
}
|
||||
if (langs.size() > 0) {
|
||||
Collections.sort(langs);
|
||||
|
@ -223,10 +230,10 @@ public class CodeSystemRenderer extends TerminologyRenderer {
|
|||
return true;
|
||||
}
|
||||
String uri = cp.getUri();
|
||||
String code = null;
|
||||
if (Utilities.noString(uri)){
|
||||
return false;
|
||||
return true; // do we always want to render properties in this case? Not sure...
|
||||
}
|
||||
String code = null;
|
||||
if (uri.contains("#")) {
|
||||
code = uri.substring(uri.indexOf("#")+1);
|
||||
uri = uri.substring(0, uri.indexOf("#"));
|
||||
|
@ -290,7 +297,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
|
|||
|
||||
|
||||
|
||||
private boolean addDefineRowToTable(XhtmlNode t, ConceptDefinitionComponent c, int level, boolean hasHierarchy, boolean hasDisplay, boolean hasDefinitions, boolean comment, boolean version, boolean deprecated, List<UsedConceptMap> maps, String system, CodeSystem cs, List<PropertyComponent> properties, CodeSystemNavigator csNav, List<String> langs) throws FHIRFormatError, DefinitionException, IOException {
|
||||
private boolean addDefineRowToTable(XhtmlNode t, ConceptDefinitionComponent c, int level, boolean hasHierarchy, boolean hasDisplay, boolean hasDefinitions, boolean comment, boolean version, boolean deprecated, List<UsedConceptMap> maps, String system, CodeSystem cs, List<PropertyComponent> properties, CodeSystemNavigator csNav, List<String> langs, boolean isSupplement) throws FHIRFormatError, DefinitionException, IOException {
|
||||
boolean hasExtensions = false;
|
||||
XhtmlNode tr = t.tr();
|
||||
XhtmlNode td = tr.td();
|
||||
|
@ -300,7 +307,12 @@ public class CodeSystemRenderer extends TerminologyRenderer {
|
|||
String s = Utilities.padLeft("", '\u00A0', level*2);
|
||||
td.addText(s);
|
||||
}
|
||||
String link = isSupplement ? getLinkForCode(cs.getSupplements(), null, c.getCode()) : null;
|
||||
if (link != null) {
|
||||
td.ah(link).attribute("style", "white-space:nowrap").addText(c.getCode());
|
||||
} else {
|
||||
td.attribute("style", "white-space:nowrap").addText(c.getCode());
|
||||
}
|
||||
XhtmlNode a;
|
||||
if (c.hasCodeElement()) {
|
||||
td.an(cs.getId()+"-" + Utilities.nmtokenize(c.getCode()));
|
||||
|
@ -450,7 +462,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
|
|||
}
|
||||
List<ConceptDefinitionComponent> ocl = csNav.getOtherChildren(c);
|
||||
for (ConceptDefinitionComponent cc : csNav.getConcepts(c)) {
|
||||
hasExtensions = addDefineRowToTable(t, cc, level+1, hasHierarchy, hasDisplay, hasDefinitions, comment, version, deprecated, maps, system, cs, properties, csNav, langs) || hasExtensions;
|
||||
hasExtensions = addDefineRowToTable(t, cc, level+1, hasHierarchy, hasDisplay, hasDefinitions, comment, version, deprecated, maps, system, cs, properties, csNav, langs, isSupplement) || hasExtensions;
|
||||
}
|
||||
for (ConceptDefinitionComponent cc : ocl) {
|
||||
tr = t.tr();
|
||||
|
|
|
@ -2,7 +2,18 @@ package org.hl7.fhir.r5.renderers;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.math.BigDecimal;
|
||||
import java.text.DateFormat;
|
||||
import java.text.NumberFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.FormatStyle;
|
||||
import java.util.Currency;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
|
@ -29,11 +40,14 @@ import org.hl7.fhir.r5.model.ContactPoint.ContactPointSystem;
|
|||
import org.hl7.fhir.r5.model.DataType;
|
||||
import org.hl7.fhir.r5.model.DateTimeType;
|
||||
import org.hl7.fhir.r5.model.Enumeration;
|
||||
import org.hl7.fhir.r5.model.Expression;
|
||||
import org.hl7.fhir.r5.model.Extension;
|
||||
import org.hl7.fhir.r5.model.HumanName;
|
||||
import org.hl7.fhir.r5.model.HumanName.NameUse;
|
||||
import org.hl7.fhir.r5.model.IdType;
|
||||
import org.hl7.fhir.r5.model.Identifier;
|
||||
import org.hl7.fhir.r5.model.InstantType;
|
||||
import org.hl7.fhir.r5.model.MarkdownType;
|
||||
import org.hl7.fhir.r5.model.Money;
|
||||
import org.hl7.fhir.r5.model.Period;
|
||||
import org.hl7.fhir.r5.model.PrimitiveType;
|
||||
import org.hl7.fhir.r5.model.Quantity;
|
||||
|
@ -63,6 +77,9 @@ import org.hl7.fhir.utilities.validation.ValidationOptions;
|
|||
import org.hl7.fhir.utilities.xhtml.NodeType;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlParser;
|
||||
|
||||
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||
|
||||
import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator;
|
||||
import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Piece;
|
||||
|
||||
|
@ -372,6 +389,8 @@ public class DataRenderer extends Renderer {
|
|||
return displayTiming((Timing) type);
|
||||
} else if (type instanceof SampledData) {
|
||||
return displaySampledData((SampledData) type);
|
||||
} else if (type.isDateTime()) {
|
||||
return displayDateTime((BaseDateTimeType) type);
|
||||
} else if (type.isPrimitive()) {
|
||||
return type.primitiveValue();
|
||||
} else {
|
||||
|
@ -379,11 +398,58 @@ public class DataRenderer extends Renderer {
|
|||
}
|
||||
}
|
||||
|
||||
private String displayDateTime(BaseDateTimeType type) {
|
||||
if (!type.hasPrimitiveValue()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// relevant inputs in rendering context:
|
||||
// timeZone, dateTimeFormat, locale, mode
|
||||
// timezone - application specified timezone to use.
|
||||
// null = default to the time of the date/time itself
|
||||
// dateTimeFormat - application specified format for date times
|
||||
// null = default to ... depends on mode
|
||||
// mode - if rendering mode is technical, format defaults to XML format
|
||||
// locale - otherwise, format defaults to SHORT for the Locale (which defaults to default Locale)
|
||||
if (isOnlyDate(type.getPrecision())) {
|
||||
DateTimeFormatter fmt = context.getDateFormat();
|
||||
if (fmt == null) {
|
||||
if (context.isTechnicalMode()) {
|
||||
fmt = DateTimeFormatter.ISO_DATE;
|
||||
} else {
|
||||
fmt = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).withLocale(context.getLocale());
|
||||
}
|
||||
}
|
||||
|
||||
LocalDate date = LocalDate.of(type.getYear(), type.getMonth()+1, type.getDay());
|
||||
return fmt.format(date);
|
||||
}
|
||||
|
||||
DateTimeFormatter fmt = context.getDateTimeFormat();
|
||||
if (fmt == null) {
|
||||
if (context.isTechnicalMode()) {
|
||||
fmt = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
|
||||
} else {
|
||||
fmt = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).withLocale(context.getLocale());
|
||||
}
|
||||
}
|
||||
ZonedDateTime zdt = ZonedDateTime.parse(type.primitiveValue());
|
||||
ZoneId zone = context.getTimeZoneId();
|
||||
if (zone != null) {
|
||||
zdt = zdt.withZoneSameInstant(zone);
|
||||
}
|
||||
return fmt.format(zdt);
|
||||
}
|
||||
|
||||
private boolean isOnlyDate(TemporalPrecisionEnum temporalPrecisionEnum) {
|
||||
return temporalPrecisionEnum == TemporalPrecisionEnum.YEAR || temporalPrecisionEnum == TemporalPrecisionEnum.MONTH || temporalPrecisionEnum == TemporalPrecisionEnum.DAY;
|
||||
}
|
||||
|
||||
public String display(BaseWrapper type) {
|
||||
return "to do";
|
||||
}
|
||||
|
||||
public void render(XhtmlNode x, BaseWrapper type) {
|
||||
public void render(XhtmlNode x, BaseWrapper type) throws FHIRFormatError, DefinitionException, IOException {
|
||||
Base base = null;
|
||||
try {
|
||||
base = type.getBase();
|
||||
|
@ -398,7 +464,7 @@ public class DataRenderer extends Renderer {
|
|||
}
|
||||
}
|
||||
|
||||
public void renderBase(XhtmlNode x, Base b) {
|
||||
public void renderBase(XhtmlNode x, Base b) throws FHIRFormatError, DefinitionException, IOException {
|
||||
if (b instanceof DataType) {
|
||||
render(x, (DataType) b);
|
||||
} else {
|
||||
|
@ -406,9 +472,9 @@ public class DataRenderer extends Renderer {
|
|||
}
|
||||
}
|
||||
|
||||
public void render(XhtmlNode x, DataType type) {
|
||||
if (type instanceof DateTimeType) {
|
||||
renderDateTime(x, (DateTimeType) type);
|
||||
public void render(XhtmlNode x, DataType type) throws FHIRFormatError, DefinitionException, IOException {
|
||||
if (type instanceof BaseDateTimeType) {
|
||||
x.tx(displayDateTime((BaseDateTimeType) type));
|
||||
} else if (type instanceof UriType) {
|
||||
renderUri(x, (UriType) type);
|
||||
} else if (type instanceof Annotation) {
|
||||
|
@ -423,6 +489,10 @@ public class DataRenderer extends Renderer {
|
|||
renderHumanName(x, (HumanName) type);
|
||||
} else if (type instanceof Address) {
|
||||
renderAddress(x, (Address) type);
|
||||
} else if (type instanceof Expression) {
|
||||
renderExpression(x, (Expression) type);
|
||||
} else if (type instanceof Money) {
|
||||
renderMoney(x, (Money) type);
|
||||
} else if (type instanceof ContactPoint) {
|
||||
renderContactPoint(x, (ContactPoint) type);
|
||||
} else if (type instanceof Quantity) {
|
||||
|
@ -437,10 +507,8 @@ public class DataRenderer extends Renderer {
|
|||
renderSampledData(x, (SampledData) type);
|
||||
} else if (type instanceof Reference) {
|
||||
renderReference(x, (Reference) type);
|
||||
} else if (type instanceof InstantType) {
|
||||
x.tx(((InstantType) type).toHumanDisplay());
|
||||
} else if (type instanceof BaseDateTimeType) {
|
||||
x.tx(((BaseDateTimeType) type).toHumanDisplay());
|
||||
} else if (type instanceof MarkdownType) {
|
||||
addMarkdown(x, ((MarkdownType) type).asStringValue());
|
||||
} else if (type.isPrimitive()) {
|
||||
x.tx(type.primitiveValue());
|
||||
} else {
|
||||
|
@ -460,22 +528,24 @@ public class DataRenderer extends Renderer {
|
|||
|
||||
public void renderDateTime(XhtmlNode x, Base e) {
|
||||
if (e.hasPrimitiveValue()) {
|
||||
x.addText(((DateTimeType) e).toHumanDisplay());
|
||||
x.addText(displayDateTime((DateTimeType) e));
|
||||
}
|
||||
}
|
||||
|
||||
public void renderDateTime(XhtmlNode x, String s) {
|
||||
if (s != null) {
|
||||
DateTimeType dt = new DateTimeType(s);
|
||||
x.addText(dt.toHumanDisplay());
|
||||
x.addText(displayDateTime(dt));
|
||||
}
|
||||
}
|
||||
|
||||
protected void renderUri(XhtmlNode x, UriType uri) {
|
||||
if (uri.getValue().startsWith("mailto:")) {
|
||||
x.ah(uri.getValue()).addText(uri.getValue().substring(7));
|
||||
} else {
|
||||
} else if (Utilities.isAbsoluteUrlLinkable(uri.getValue()) && !(uri instanceof IdType)) {
|
||||
x.ah(uri.getValue()).addText(uri.getValue());
|
||||
} else {
|
||||
x.addText(uri.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -641,6 +711,38 @@ public class DataRenderer extends Renderer {
|
|||
}
|
||||
}
|
||||
|
||||
protected String getLinkForCode(String system, String version, String code) {
|
||||
if ("http://snomed.info/sct".equals(system)) {
|
||||
if (!Utilities.noString(code)) {
|
||||
return "http://snomed.info/id/"+code;
|
||||
} else {
|
||||
return "https://browser.ihtsdotools.org/";
|
||||
}
|
||||
} else if ("http://loinc.org".equals(system)) {
|
||||
if (!Utilities.noString(code)) {
|
||||
return "https://loinc.org/"+code;
|
||||
} else {
|
||||
return "https://loinc.org/";
|
||||
}
|
||||
} else if ("http://www.nlm.nih.gov/research/umls/rxnorm".equals(system)) {
|
||||
if (!Utilities.noString(code)) {
|
||||
return "https://mor.nlm.nih.gov/RxNav/search?searchBy=RXCUI&searchTerm="+code;
|
||||
} else {
|
||||
return "https://www.nlm.nih.gov/research/umls/rxnorm/index.html";
|
||||
}
|
||||
} else {
|
||||
CodeSystem cs = context.getWorker().fetchCodeSystem(system, version);
|
||||
if (cs != null && cs.hasUserData("path")) {
|
||||
if (!Utilities.noString(code)) {
|
||||
return cs.getUserString("path")+"#"+Utilities.nmtokenize(code);
|
||||
} else {
|
||||
return cs.getUserString("path");
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void renderCodingWithDetails(XhtmlNode x, Coding c) {
|
||||
String s = "";
|
||||
if (c.hasDisplayElement())
|
||||
|
@ -650,22 +752,13 @@ public class DataRenderer extends Renderer {
|
|||
|
||||
|
||||
String sn = describeSystem(c.getSystem());
|
||||
if ("http://snomed.info/sct".equals(c.getSystem())) {
|
||||
if (c.hasCode()) {
|
||||
x.ah("http://snomed.info/id/"+c.getCode()).tx(sn);
|
||||
} else {
|
||||
x.ah("https://browser.ihtsdotools.org/").tx(sn);
|
||||
}
|
||||
} else if ("http://loinc.org".equals(c.getSystem())) {
|
||||
x.ah("https://loinc.org/").tx(sn);
|
||||
} else {
|
||||
CodeSystem cs = context.getWorker().fetchCodeSystem(c.getSystem());
|
||||
if (cs != null && cs.hasUserData("path")) {
|
||||
x.ah(cs.getUserString("path")).tx(sn);
|
||||
String link = getLinkForCode(c.getSystem(), c.getVersion(), c.getCode());
|
||||
if (link != null) {
|
||||
x.ah(link).tx(sn);
|
||||
} else {
|
||||
x.tx(sn);
|
||||
}
|
||||
}
|
||||
|
||||
x.tx(" ");
|
||||
x.tx(c.getCode());
|
||||
if (!Utilities.noString(s)) {
|
||||
|
@ -903,6 +996,57 @@ public class DataRenderer extends Renderer {
|
|||
return s.toString();
|
||||
}
|
||||
|
||||
protected String getLocalizedBigDecimalValue(BigDecimal input, Currency c) {
|
||||
NumberFormat numberFormat = NumberFormat.getNumberInstance(context.getLocale());
|
||||
numberFormat.setGroupingUsed(true);
|
||||
numberFormat.setMaximumFractionDigits(c.getDefaultFractionDigits());
|
||||
numberFormat.setMinimumFractionDigits(c.getDefaultFractionDigits());
|
||||
return numberFormat.format(input);
|
||||
}
|
||||
|
||||
protected void renderMoney(XhtmlNode x, Money money) {
|
||||
Currency c = Currency.getInstance(money.getCurrency());
|
||||
if (c != null) {
|
||||
XhtmlNode s = x.span(null, c.getDisplayName());
|
||||
s.tx(c.getSymbol(context.getLocale()));
|
||||
s.tx(getLocalizedBigDecimalValue(money.getValue(), c));
|
||||
x.tx(" ("+c.getCurrencyCode()+")");
|
||||
} else {
|
||||
x.tx(money.getCurrency());
|
||||
x.tx(money.getValue().toPlainString());
|
||||
}
|
||||
}
|
||||
|
||||
protected void renderExpression(XhtmlNode x, Expression expr) {
|
||||
// there's two parts: what the expression is, and how it's described.
|
||||
// we start with what it is, and then how it's desceibed
|
||||
if (expr.hasExpression()) {
|
||||
XhtmlNode c = x;
|
||||
if (expr.hasReference()) {
|
||||
c = x.ah(expr.getReference());
|
||||
}
|
||||
if (expr.hasLanguage()) {
|
||||
c = c.span(null, expr.getLanguage());
|
||||
}
|
||||
c.code().tx(expr.getExpression());
|
||||
} else if (expr.hasReference()) {
|
||||
x.ah(expr.getReference()).tx("source");
|
||||
}
|
||||
if (expr.hasName() || expr.hasDescription()) {
|
||||
x.tx("(");
|
||||
if (expr.hasName()) {
|
||||
x.b().tx(expr.getName());
|
||||
}
|
||||
if (expr.hasDescription()) {
|
||||
x.tx("\"");
|
||||
x.tx(expr.getDescription());
|
||||
x.tx("\"");
|
||||
}
|
||||
x.tx(")");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void renderContactPoint(XhtmlNode x, ContactPoint contact) {
|
||||
if (contact != null) {
|
||||
if (!contact.hasSystem()) {
|
||||
|
@ -1046,19 +1190,19 @@ public class DataRenderer extends Renderer {
|
|||
x.tx(" "+q.getLow().getUnit());
|
||||
}
|
||||
|
||||
public static String displayPeriod(Period p) {
|
||||
String s = !p.hasStart() ? "(?)" : p.getStartElement().toHumanDisplay();
|
||||
public String displayPeriod(Period p) {
|
||||
String s = !p.hasStart() ? "(?)" : displayDateTime(p.getStartElement());
|
||||
s = s + " --> ";
|
||||
return s + (!p.hasEnd() ? "(ongoing)" : p.getEndElement().toHumanDisplay());
|
||||
return s + (!p.hasEnd() ? "(ongoing)" : displayDateTime(p.getEndElement()));
|
||||
}
|
||||
|
||||
public void renderPeriod(XhtmlNode x, Period p) {
|
||||
x.addText(!p.hasStart() ? "??" : p.getStartElement().toHumanDisplay());
|
||||
x.addText(!p.hasStart() ? "??" : displayDateTime(p.getStartElement()));
|
||||
x.tx(" --> ");
|
||||
x.addText(!p.hasEnd() ? "(ongoing)" : p.getEndElement().toHumanDisplay());
|
||||
x.addText(!p.hasEnd() ? "(ongoing)" : displayDateTime(p.getEndElement()));
|
||||
}
|
||||
|
||||
public void renderDataRequirement(XhtmlNode x, DataRequirement dr) {
|
||||
public void renderDataRequirement(XhtmlNode x, DataRequirement dr) throws FHIRFormatError, DefinitionException, IOException {
|
||||
XhtmlNode tbl = x.table("grid");
|
||||
XhtmlNode tr = tbl.tr();
|
||||
XhtmlNode td = tr.td().colspan("2");
|
||||
|
@ -1163,7 +1307,7 @@ public class DataRenderer extends Renderer {
|
|||
CommaSeparatedStringBuilder c = new CommaSeparatedStringBuilder();
|
||||
for (DateTimeType p : s.getEvent()) {
|
||||
if (p.hasValue()) {
|
||||
c.append(p.toHumanDisplay());
|
||||
c.append(displayDateTime(p));
|
||||
} else if (!renderExpression(c, p)) {
|
||||
c.append("??");
|
||||
}
|
||||
|
@ -1174,7 +1318,7 @@ public class DataRenderer extends Renderer {
|
|||
if (s.hasRepeat()) {
|
||||
TimingRepeatComponent rep = s.getRepeat();
|
||||
if (rep.hasBoundsPeriod() && rep.getBoundsPeriod().hasStart())
|
||||
b.append("Starting "+rep.getBoundsPeriod().getStartElement().toHumanDisplay());
|
||||
b.append("Starting "+displayDateTime(rep.getBoundsPeriod().getStartElement()));
|
||||
if (rep.hasCount())
|
||||
b.append("Count "+Integer.toString(rep.getCount())+" times");
|
||||
if (rep.hasDuration())
|
||||
|
@ -1206,7 +1350,7 @@ public class DataRenderer extends Renderer {
|
|||
b.append("Do "+st);
|
||||
}
|
||||
if (rep.hasBoundsPeriod() && rep.getBoundsPeriod().hasEnd())
|
||||
b.append("Until "+rep.getBoundsPeriod().getEndElement().toHumanDisplay());
|
||||
b.append("Until "+displayDateTime(rep.getBoundsPeriod().getEndElement()));
|
||||
}
|
||||
return b.toString();
|
||||
}
|
||||
|
|
|
@ -59,7 +59,8 @@ public class ListRenderer extends ResourceRenderer {
|
|||
shortForRef(td, list.get("subject"));
|
||||
}
|
||||
if (list.has("encounter")) {
|
||||
shortForRef(td.tx("Encounter: "), list.get("encounter"));
|
||||
td.tx("Encounter: ");
|
||||
shortForRef(td, list.get("encounter"));
|
||||
}
|
||||
if (list.has("source")) {
|
||||
td.tx("Source: ");
|
||||
|
|
|
@ -33,12 +33,14 @@ import org.hl7.fhir.r5.model.DomainResource;
|
|||
import org.hl7.fhir.r5.model.Dosage;
|
||||
import org.hl7.fhir.r5.model.ElementDefinition;
|
||||
import org.hl7.fhir.r5.model.Enumeration;
|
||||
import org.hl7.fhir.r5.model.Expression;
|
||||
import org.hl7.fhir.r5.model.Extension;
|
||||
import org.hl7.fhir.r5.model.HumanName;
|
||||
import org.hl7.fhir.r5.model.IdType;
|
||||
import org.hl7.fhir.r5.model.Identifier;
|
||||
import org.hl7.fhir.r5.model.InstantType;
|
||||
import org.hl7.fhir.r5.model.Meta;
|
||||
import org.hl7.fhir.r5.model.Money;
|
||||
import org.hl7.fhir.r5.model.Narrative;
|
||||
import org.hl7.fhir.r5.model.Narrative.NarrativeStatus;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
|
||||
|
@ -118,6 +120,7 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
|
|||
generateByProfile(r, sd, r.root(), sd.getSnapshot().getElement(), ed, context.getProfileUtilities().getChildList(sd, ed), x, r.fhirType(), context.isTechnicalMode(), 0);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("Error Generating Narrative for "+r.fhirType()+"/"+r.getId()+": "+e.getMessage());
|
||||
e.printStackTrace();
|
||||
x.para().b().style("color: maroon").tx("Exception generating Narrative: "+e.getMessage());
|
||||
}
|
||||
|
@ -291,7 +294,6 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
|
|||
if (ew == null)
|
||||
return;
|
||||
|
||||
|
||||
Base e = ew.getBase();
|
||||
|
||||
if (e instanceof StringType)
|
||||
|
@ -308,9 +310,12 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
|
|||
renderDateTime(x, e);
|
||||
} else if (e instanceof Base64BinaryType)
|
||||
x.addText(new Base64().encodeAsString(((Base64BinaryType) e).getValue()));
|
||||
else if (e instanceof org.hl7.fhir.r5.model.DateType)
|
||||
else if (e instanceof org.hl7.fhir.r5.model.DateType) {
|
||||
org.hl7.fhir.r5.model.DateType dt = ((org.hl7.fhir.r5.model.DateType) e);
|
||||
if (((org.hl7.fhir.r5.model.DateType) e).hasValue()) {
|
||||
x.addText(((org.hl7.fhir.r5.model.DateType) e).toHumanDisplay());
|
||||
else if (e instanceof Enumeration) {
|
||||
}
|
||||
} else if (e instanceof Enumeration) {
|
||||
Object ev = ((Enumeration<?>) e).getValue();
|
||||
x.addText(ev == null ? "" : ev.toString()); // todo: look up a display name if there is one
|
||||
} else if (e instanceof BooleanType) {
|
||||
|
@ -347,6 +352,10 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
|
|||
renderAddress(x, (Address) e);
|
||||
} else if (e instanceof ContactPoint) {
|
||||
renderContactPoint(x, (ContactPoint) e);
|
||||
} else if (e instanceof Expression) {
|
||||
renderExpression(x, (Expression) e);
|
||||
} else if (e instanceof Money) {
|
||||
renderMoney(x, (Money) e);
|
||||
} else if (e instanceof ContactDetail) {
|
||||
ContactDetail cd = (ContactDetail) e;
|
||||
if (cd.hasName()) {
|
||||
|
|
|
@ -703,7 +703,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer {
|
|||
}
|
||||
if (i.hasAnswerValueSet()) {
|
||||
XhtmlNode ans = item(ul, "Answers");
|
||||
if (Utilities.noString(i.getAnswerValueSet()) && i.getAnswerValueSet().startsWith("#")) {
|
||||
if (!Utilities.noString(i.getAnswerValueSet()) && i.getAnswerValueSet().startsWith("#")) {
|
||||
ValueSet vs = (ValueSet) q.getContained(i.getAnswerValueSet().substring(1));
|
||||
if (vs == null) {
|
||||
ans.tx(i.getAnswerValueSet());
|
||||
|
@ -792,7 +792,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer {
|
|||
private void listOptions(Questionnaire q, QuestionnaireItemComponent i, XhtmlNode select) {
|
||||
if (i.hasAnswerValueSet()) {
|
||||
ValueSet vs = null;
|
||||
if (Utilities.noString(i.getAnswerValueSet()) && i.getAnswerValueSet().startsWith("#")) {
|
||||
if (!Utilities.noString(i.getAnswerValueSet()) && i.getAnswerValueSet().startsWith("#")) {
|
||||
vs = (ValueSet) q.getContained(i.getAnswerValueSet().substring(1));
|
||||
if (vs != null && !vs.hasUrl()) {
|
||||
vs = vs.copy();
|
||||
|
|
|
@ -214,6 +214,11 @@ public abstract class ResourceRenderer extends DataRenderer {
|
|||
if ((tr == null || !tr.getReference().startsWith("#")) && name != null) {
|
||||
x.addText(" \""+name+"\"");
|
||||
}
|
||||
if (r.hasExtension(ToolingExtensions.EXT_TARGET_ID)) {
|
||||
x.addText("(#"+r.getExtensionString(ToolingExtensions.EXT_TARGET_ID)+")");
|
||||
} else if (r.hasExtension(ToolingExtensions.EXT_TARGET_PATH)) {
|
||||
x.addText("(#/"+r.getExtensionString(ToolingExtensions.EXT_TARGET_PATH)+")");
|
||||
}
|
||||
} else {
|
||||
if (display != null) {
|
||||
c.addText(display);
|
||||
|
@ -272,6 +277,11 @@ public abstract class ResourceRenderer extends DataRenderer {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
String version = null;
|
||||
if (url.contains("/_history/")) {
|
||||
version = url.substring(url.indexOf("/_history/")+10);
|
||||
url = url.substring(0, url.indexOf("/_history/"));
|
||||
}
|
||||
|
||||
if (rcontext != null) {
|
||||
BundleEntryComponent bundleResource = rcontext.resolve(url);
|
||||
|
@ -279,7 +289,7 @@ public abstract class ResourceRenderer extends DataRenderer {
|
|||
String bundleUrl = "#" + bundleResource.getResource().getResourceType().name() + "_" + bundleResource.getResource().getId();
|
||||
return new ResourceWithReference(bundleUrl, new ResourceWrapperDirect(this.context, bundleResource.getResource()));
|
||||
}
|
||||
org.hl7.fhir.r5.elementmodel.Element bundleElement = rcontext.resolveElement(url);
|
||||
org.hl7.fhir.r5.elementmodel.Element bundleElement = rcontext.resolveElement(url, version);
|
||||
if (bundleElement != null) {
|
||||
String bundleUrl = null;
|
||||
Element br = bundleElement.getNamedChild("resource");
|
||||
|
@ -292,7 +302,7 @@ public abstract class ResourceRenderer extends DataRenderer {
|
|||
}
|
||||
}
|
||||
|
||||
Resource ae = getContext().getWorker().fetchResource(null, url);
|
||||
Resource ae = getContext().getWorker().fetchResource(null, url, version);
|
||||
if (ae != null)
|
||||
return new ResourceWithReference(url, new ResourceWrapperDirect(this.context, ae));
|
||||
else if (context.getResolver() != null) {
|
||||
|
@ -473,10 +483,10 @@ public abstract class ResourceRenderer extends DataRenderer {
|
|||
}
|
||||
|
||||
private String getPrimitiveValue(BaseWrapper b, String name) throws UnsupportedEncodingException, FHIRException, IOException {
|
||||
return b != null && b.getChildByName(name).hasValues() ? b.getChildByName(name).getValues().get(0).getBase().primitiveValue() : null;
|
||||
return b != null && b.has(name) && b.getChildByName(name).hasValues() ? b.getChildByName(name).getValues().get(0).getBase().primitiveValue() : null;
|
||||
}
|
||||
|
||||
private String getPrimitiveValue(ResourceWrapper r, String name) throws UnsupportedEncodingException, FHIRException, IOException {
|
||||
return r.getChildByName(name).hasValues() ? r.getChildByName(name).getValues().get(0).getBase().primitiveValue() : null;
|
||||
return r.has(name) && r.getChildByName(name).hasValues() ? r.getChildByName(name).getValues().get(0).getBase().primitiveValue() : null;
|
||||
}
|
||||
}
|
|
@ -176,23 +176,8 @@ public class ValueSetRenderer extends TerminologyRenderer {
|
|||
else
|
||||
x.para().tx("This value set contains "+count.toString()+" concepts");
|
||||
}
|
||||
if (ToolingExtensions.hasExtension(vs.getExpansion(), ToolingExtensions.EXT_EXP_FRAGMENT)) {
|
||||
XhtmlNode div = x.div().style("border: maroon 1px solid; background-color: #FFCCCC; padding: 8px");
|
||||
List<Extension> exl = vs.getExpansion().getExtensionsByUrl(ToolingExtensions.EXT_EXP_FRAGMENT);
|
||||
if (exl.size() > 1) {
|
||||
div.para().addText("Warning: this expansion is generated from fragments of the following code systems, and may be missing codes, or include codes that are not valid:");
|
||||
XhtmlNode ul = div.ul();
|
||||
for (Extension ex : exl) {
|
||||
addCSRef(ul.li(), ex.getValue().primitiveValue());
|
||||
}
|
||||
} else {
|
||||
XhtmlNode p = div.para();
|
||||
p.addText("Warning: this expansion is generated from a fragment of the code system ");
|
||||
addCSRef(p, exl.get(0).getValue().primitiveValue());
|
||||
p.addText(" and may be missing codes, or include codes that are not valid");
|
||||
}
|
||||
}
|
||||
|
||||
generateContentModeNotices(x, vs.getExpansion());
|
||||
generateVersionNotice(x, vs.getExpansion());
|
||||
|
||||
CodeSystem allCS = null;
|
||||
|
@ -273,6 +258,46 @@ public class ValueSetRenderer extends TerminologyRenderer {
|
|||
return hasExtensions;
|
||||
}
|
||||
|
||||
private void generateContentModeNotices(XhtmlNode x, ValueSetExpansionComponent expansion) {
|
||||
generateContentModeNotice(x, expansion, "example", "Expansion based on example code system");
|
||||
generateContentModeNotice(x, expansion, "fragment", "Expansion based on code system fragment");
|
||||
}
|
||||
|
||||
private void generateContentModeNotice(XhtmlNode x, ValueSetExpansionComponent expansion, String mode, String text) {
|
||||
Multimap<String, String> versions = HashMultimap.create();
|
||||
for (ValueSetExpansionParameterComponent p : expansion.getParameter()) {
|
||||
if (p.getName().equals(mode)) {
|
||||
String[] parts = ((PrimitiveType) p.getValue()).asStringValue().split("\\|");
|
||||
if (parts.length == 2)
|
||||
versions.put(parts[0], parts[1]);
|
||||
}
|
||||
}
|
||||
if (versions.size() > 0) {
|
||||
XhtmlNode div = null;
|
||||
XhtmlNode ul = null;
|
||||
boolean first = true;
|
||||
for (String s : versions.keySet()) {
|
||||
if (versions.size() == 1 && versions.get(s).size() == 1) {
|
||||
for (String v : versions.get(s)) { // though there'll only be one
|
||||
XhtmlNode p = x.para().style("border: black 1px dotted; background-color: #ffcccc; padding: 8px; margin-bottom: 8px");
|
||||
p.tx(text+" ");
|
||||
expRef(p, s, v);
|
||||
}
|
||||
} else {
|
||||
for (String v : versions.get(s)) {
|
||||
if (first) {
|
||||
div = x.div().style("border: black 1px dotted; background-color: #EEEEEE; padding: 8px; margin-bottom: 8px");
|
||||
div.para().tx(text+"s: ");
|
||||
ul = div.ul();
|
||||
first = false;
|
||||
}
|
||||
expRef(ul.li(), s, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkDoSystem(ValueSet vs, ValueSet src) {
|
||||
if (src != null)
|
||||
vs = src;
|
||||
|
|
|
@ -49,7 +49,7 @@ public class DOMWrappers {
|
|||
|
||||
@Override
|
||||
public Base getBase() throws UnsupportedEncodingException, IOException, FHIRException {
|
||||
if (type == null || type.equals("Resource") || type.equals("BackboneElement") || type.equals("Element"))
|
||||
if (Utilities.noString(type) || type.equals("Resource") || type.equals("BackboneElement") || type.equals("Element"))
|
||||
return null;
|
||||
|
||||
String xml;
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
package org.hl7.fhir.r5.renderers.utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.DateFormat;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.FormatStyle;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||
|
@ -117,6 +123,11 @@ public class RenderingContext {
|
|||
private boolean addGeneratedNarrativeHeader = true;
|
||||
|
||||
private FhirPublication targetVersion;
|
||||
private Locale locale;
|
||||
private ZoneId timeZoneId;
|
||||
private DateTimeFormatter dateTimeFormat;
|
||||
private DateTimeFormatter dateFormat;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param context - access to all related resources that might be needed
|
||||
|
@ -136,6 +147,8 @@ public class RenderingContext {
|
|||
if (terminologyServiceOptions != null) {
|
||||
this.terminologyServiceOptions = terminologyServiceOptions;
|
||||
}
|
||||
// default to US locale - discussion here: https://github.com/hapifhir/org.hl7.fhir.core/issues/666
|
||||
this.locale = new Locale.Builder().setLanguageTag("en-US").build();
|
||||
profileUtilities = new ProfileUtilities(worker, null, null);
|
||||
}
|
||||
|
||||
|
@ -427,4 +440,79 @@ public class RenderingContext {
|
|||
return mode == ResourceRendererMode.TECHNICAL;
|
||||
}
|
||||
|
||||
public boolean hasLocale() {
|
||||
return locale != null;
|
||||
}
|
||||
|
||||
public Locale getLocale() {
|
||||
if (locale == null) {
|
||||
return Locale.getDefault();
|
||||
} else {
|
||||
return locale;
|
||||
}
|
||||
}
|
||||
|
||||
public void setLocale(Locale locale) {
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* if the timezone is null, the rendering will default to the source timezone
|
||||
* in the resource
|
||||
*
|
||||
* Note that if you're working server side, the FHIR project recommends the use
|
||||
* of the Date header so that clients know what timezone the server defaults to,
|
||||
*
|
||||
* There is no standard way for the server to know what the client timezone is.
|
||||
* In the case where the client timezone is unknown, the timezone should be null
|
||||
*
|
||||
* @return the specified timezone to render in
|
||||
*/
|
||||
public ZoneId getTimeZoneId() {
|
||||
return timeZoneId;
|
||||
}
|
||||
|
||||
public void setTimeZoneId(ZoneId timeZoneId) {
|
||||
this.timeZoneId = timeZoneId;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* In the absence of a specified format, the renderers will default to
|
||||
* the FormatStyle.MEDIUM for the current locale.
|
||||
*
|
||||
* @return the format to use
|
||||
*/
|
||||
public DateTimeFormatter getDateTimeFormat() {
|
||||
return this.dateTimeFormat;
|
||||
}
|
||||
|
||||
public void setDateTimeFormat(DateTimeFormatter dateTimeFormat) {
|
||||
this.dateTimeFormat = dateTimeFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* In the absence of a specified format, the renderers will default to
|
||||
* the FormatStyle.MEDIUM for the current locale.
|
||||
*
|
||||
* @return the format to use
|
||||
*/
|
||||
public DateTimeFormatter getDateFormat() {
|
||||
return this.dateFormat;
|
||||
}
|
||||
|
||||
public void setDateFormat(DateTimeFormatter dateFormat) {
|
||||
this.dateFormat = dateFormat;
|
||||
}
|
||||
|
||||
public ResourceRendererMode getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public void setMode(ResourceRendererMode mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -101,7 +101,7 @@ public class Resolver {
|
|||
return null;
|
||||
}
|
||||
|
||||
public org.hl7.fhir.r5.elementmodel.Element resolveElement(String value) {
|
||||
public org.hl7.fhir.r5.elementmodel.Element resolveElement(String value, String version) {
|
||||
if (value.startsWith("#")) {
|
||||
if (resourceElement != null) {
|
||||
for (org.hl7.fhir.r5.elementmodel.Element r : resourceElement.getChildrenByName("contained")) {
|
||||
|
@ -115,24 +115,46 @@ public class Resolver {
|
|||
if (containerElement != null) {
|
||||
for (org.hl7.fhir.r5.elementmodel.Element be : containerElement.getChildren("entry")) {
|
||||
org.hl7.fhir.r5.elementmodel.Element res = be.getNamedChild("resource");
|
||||
if (value.equals(be.getChildValue("fullUrl")))
|
||||
if (res != null) {
|
||||
if (value.equals(be.getChildValue("fullUrl"))) {
|
||||
if (checkVersion(version, res)) {
|
||||
return be;
|
||||
if (value.equals(res.fhirType()+"/"+res.getChildValue("id")))
|
||||
}
|
||||
}
|
||||
if (value.equals(res.fhirType()+"/"+res.getChildValue("id"))) {
|
||||
if (checkVersion(version, res)) {
|
||||
return be;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (type == ResourceContextType.PARAMETERS) {
|
||||
if (containerElement != null) {
|
||||
for (org.hl7.fhir.r5.elementmodel.Element p : containerElement.getChildren("parameter")) {
|
||||
org.hl7.fhir.r5.elementmodel.Element res = p.getNamedChild("resource");
|
||||
if (res != null && value.equals(res.fhirType()+"/"+res.getChildValue("id")))
|
||||
if (res != null && value.equals(res.fhirType()+"/"+res.getChildValue("id"))) {
|
||||
if (checkVersion(version, res)) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean checkVersion(String version, org.hl7.fhir.r5.elementmodel.Element res) {
|
||||
if (version == null) {
|
||||
return true;
|
||||
} else if (!res.hasChild("meta")) {
|
||||
return false;
|
||||
} else {
|
||||
org.hl7.fhir.r5.elementmodel.Element meta = res.getNamedChild("meta");
|
||||
return version.equals(meta.getChildValue("version"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class ResourceWithReference {
|
||||
|
|
|
@ -33,6 +33,8 @@ package org.hl7.fhir.r5.terminologies;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
@ -51,6 +53,7 @@ import org.hl7.fhir.r5.model.CodeType;
|
|||
import org.hl7.fhir.r5.model.DataType;
|
||||
import org.hl7.fhir.r5.model.DateTimeType;
|
||||
import org.hl7.fhir.r5.model.Enumerations.PublicationStatus;
|
||||
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities.ConceptDefinitionComponentSorter;
|
||||
import org.hl7.fhir.r5.model.Identifier;
|
||||
import org.hl7.fhir.r5.model.Meta;
|
||||
import org.hl7.fhir.r5.model.UriType;
|
||||
|
@ -60,6 +63,15 @@ import org.hl7.fhir.utilities.Utilities;
|
|||
|
||||
public class CodeSystemUtilities {
|
||||
|
||||
public static class ConceptDefinitionComponentSorter implements Comparator<ConceptDefinitionComponent> {
|
||||
|
||||
@Override
|
||||
public int compare(ConceptDefinitionComponent o1, ConceptDefinitionComponent o2) {
|
||||
return o1.getCode().compareTo(o2.getCode());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static final String USER_DATA_CROSS_LINK = "cs.utils.cross.link";
|
||||
|
||||
public static class CodeSystemNavigator {
|
||||
|
@ -128,7 +140,7 @@ public class CodeSystemUtilities {
|
|||
private List<String> getSubsumedBy(ConceptDefinitionComponent cd) {
|
||||
List<String> codes = new ArrayList<>();
|
||||
for (ConceptPropertyComponent cp : cd.getProperty()) {
|
||||
if (cp.getCode().equals("subsumedBy")) {
|
||||
if ("subsumedBy".equals(cp.getCode())) {
|
||||
codes.add(cp.getValue().primitiveValue());
|
||||
}
|
||||
}
|
||||
|
@ -149,7 +161,7 @@ public class CodeSystemUtilities {
|
|||
|
||||
public static boolean isNotSelectable(CodeSystem cs, ConceptDefinitionComponent def) {
|
||||
for (ConceptPropertyComponent p : def.getProperty()) {
|
||||
if (p.getCode().equals("notSelectable") && p.hasValue() && p.getValue() instanceof BooleanType)
|
||||
if ("notSelectable".equals(p.getCode()) && p.hasValue() && p.getValue() instanceof BooleanType)
|
||||
return ((BooleanType) p.getValue()).getValue();
|
||||
}
|
||||
return false;
|
||||
|
@ -212,14 +224,14 @@ public class CodeSystemUtilities {
|
|||
try {
|
||||
for (ConceptPropertyComponent p : def.getProperty()) {
|
||||
if (!ignoreStatus) {
|
||||
if (p.getCode().equals("status") && p.hasValue() && p.hasValueCodeType() && p.getValueCodeType().getCode().equals("deprecated"))
|
||||
if ("status".equals(p.getCode()) && p.hasValue() && p.hasValueCodeType() && "deprecated".equals(p.getValueCodeType().getCode()))
|
||||
return true;
|
||||
}
|
||||
// this, though status should also be set
|
||||
if (p.getCode().equals("deprecationDate") && p.hasValue() && p.getValue() instanceof DateTimeType)
|
||||
if ("deprecationDate".equals(p.getCode()) && p.hasValue() && p.getValue() instanceof DateTimeType)
|
||||
return ((DateTimeType) p.getValue()).before(new DateTimeType(Calendar.getInstance()));
|
||||
// legacy
|
||||
if (p.getCode().equals("deprecated") && p.hasValue() && p.getValue() instanceof BooleanType)
|
||||
if ("deprecated".equals(p.getCode()) && p.hasValue() && p.getValue() instanceof BooleanType)
|
||||
return ((BooleanType) p.getValue()).getValue();
|
||||
}
|
||||
return false;
|
||||
|
@ -236,7 +248,7 @@ public class CodeSystemUtilities {
|
|||
|
||||
public static boolean isInactive(CodeSystem cs, ConceptDefinitionComponent def) throws FHIRException {
|
||||
for (ConceptPropertyComponent p : def.getProperty()) {
|
||||
if (p.getCode().equals("status") && p.hasValueStringType())
|
||||
if ("status".equals(p.getCode()) && p.hasValueStringType())
|
||||
return "inactive".equals(p.getValueStringType());
|
||||
}
|
||||
return false;
|
||||
|
@ -273,10 +285,14 @@ public class CodeSystemUtilities {
|
|||
}
|
||||
|
||||
public static CodeSystem makeShareable(CodeSystem cs) {
|
||||
if (!cs.hasExperimental()) {
|
||||
cs.setExperimental(false);
|
||||
}
|
||||
|
||||
if (!cs.hasMeta())
|
||||
cs.setMeta(new Meta());
|
||||
for (UriType t : cs.getMeta().getProfile())
|
||||
if (t.getValue().equals("http://hl7.org/fhir/StructureDefinition/shareablecodesystem"))
|
||||
if ("http://hl7.org/fhir/StructureDefinition/shareablecodesystem".equals(t.getValue()))
|
||||
return cs;
|
||||
cs.getMeta().getProfile().add(new CanonicalType("http://hl7.org/fhir/StructureDefinition/shareablecodesystem"));
|
||||
return cs;
|
||||
|
@ -286,7 +302,7 @@ public class CodeSystemUtilities {
|
|||
if (!cs.hasMeta())
|
||||
cs.setMeta(new Meta());
|
||||
for (UriType t : cs.getMeta().getProfile())
|
||||
if (t.getValue().equals("http://hl7.org/fhir/StructureDefinition/shareablecodesystem"))
|
||||
if ("http://hl7.org/fhir/StructureDefinition/shareablecodesystem".equals(t.getValue()))
|
||||
return false;
|
||||
cs.getMeta().getProfile().add(new CanonicalType("http://hl7.org/fhir/StructureDefinition/shareablecodesystem"));
|
||||
return true;
|
||||
|
@ -350,9 +366,13 @@ public class CodeSystemUtilities {
|
|||
}
|
||||
if (fmm != null) {
|
||||
String sfmm = ToolingExtensions.readStringExtension(cs, ToolingExtensions.EXT_FMM_LEVEL);
|
||||
if (Utilities.noString(sfmm) || Integer.parseInt(sfmm) < Integer.parseInt(fmm))
|
||||
if (Utilities.noString(sfmm) || Integer.parseInt(sfmm) < Integer.parseInt(fmm)) {
|
||||
ToolingExtensions.setIntegerExtension(cs, ToolingExtensions.EXT_FMM_LEVEL, Integer.parseInt(fmm));
|
||||
}
|
||||
if (Integer.parseInt(fmm) <= 1) {
|
||||
cs.setExperimental(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -491,4 +511,26 @@ public class CodeSystemUtilities {
|
|||
|
||||
}
|
||||
|
||||
public static boolean hasHierarchy(CodeSystem cs) {
|
||||
for (ConceptDefinitionComponent c : cs.getConcept()) {
|
||||
if (c.hasConcept()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void sortAllCodes(CodeSystem cs) {
|
||||
sortAllCodes(cs.getConcept());
|
||||
}
|
||||
|
||||
private static void sortAllCodes(List<ConceptDefinitionComponent> list) {
|
||||
Collections.sort(list, new ConceptDefinitionComponentSorter());
|
||||
for (ConceptDefinitionComponent cd : list) {
|
||||
if (cd.hasConcept()) {
|
||||
sortAllCodes(cd.getConcept());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -17,6 +17,7 @@ import java.nio.file.Files;
|
|||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Base64;
|
||||
import java.util.Date;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
@ -75,7 +76,8 @@ public class TerminologyCacheManager {
|
|||
}
|
||||
|
||||
IniFile ini = new IniFile(Utilities.path(cacheFolder, "cache.ini"));
|
||||
ini.setStringProperty("version", "version", version, null);
|
||||
ini.setStringProperty("cache", "version", version, null);
|
||||
ini.setDateProperty("cache", "last-use", new Date(), null);
|
||||
ini.save();
|
||||
}
|
||||
|
||||
|
@ -116,7 +118,7 @@ public class TerminologyCacheManager {
|
|||
|
||||
private String getCacheVersion() throws IOException {
|
||||
IniFile ini = new IniFile(Utilities.path(cacheFolder, "cache.ini"));
|
||||
return ini.getStringProperty("version", "version");
|
||||
return ini.getStringProperty("cache", "version");
|
||||
}
|
||||
|
||||
public String getFolder() {
|
||||
|
|
|
@ -56,6 +56,9 @@ import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
|
|||
import org.hl7.fhir.r5.model.ValueSet.ConceptSetFilterComponent;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
|
||||
import org.hl7.fhir.r5.terminologies.ValueSetExpander.TerminologyServiceErrorClass;
|
||||
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
||||
import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier;
|
||||
import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier.ValidationContextResourceProxy;
|
||||
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.i18n.I18nConstants;
|
||||
|
@ -69,6 +72,8 @@ public class ValueSetCheckerSimple extends ValueSetWorker implements ValueSetChe
|
|||
private IWorkerContext context;
|
||||
private Map<String, ValueSetCheckerSimple> inner = new HashMap<>();
|
||||
private ValidationOptions options;
|
||||
private ValidationContextCarrier localContext;
|
||||
private List<CodeSystem> localSystems = new ArrayList<>();
|
||||
|
||||
public ValueSetCheckerSimple(ValidationOptions options, ValueSet source, IWorkerContext context) {
|
||||
this.valueset = source;
|
||||
|
@ -76,6 +81,44 @@ public class ValueSetCheckerSimple extends ValueSetWorker implements ValueSetChe
|
|||
this.options = options;
|
||||
}
|
||||
|
||||
public ValueSetCheckerSimple(ValidationOptions options, ValueSet source, IWorkerContext context, ValidationContextCarrier ctxt) {
|
||||
this.valueset = source;
|
||||
this.context = context;
|
||||
this.options = options;
|
||||
this.localContext = ctxt;
|
||||
analyseValueSet();
|
||||
}
|
||||
|
||||
private void analyseValueSet() {
|
||||
if (localContext != null) {
|
||||
if (valueset != null) {
|
||||
for (ConceptSetComponent i : valueset.getCompose().getInclude()) {
|
||||
analyseComponent(i);
|
||||
}
|
||||
for (ConceptSetComponent i : valueset.getCompose().getExclude()) {
|
||||
analyseComponent(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void analyseComponent(ConceptSetComponent i) {
|
||||
if (i.getSystemElement().hasExtension(ToolingExtensions.EXT_VALUESET_SYSTEM)) {
|
||||
String ref = i.getSystemElement().getExtensionString(ToolingExtensions.EXT_VALUESET_SYSTEM);
|
||||
if (ref.startsWith("#")) {
|
||||
String id = ref.substring(1);
|
||||
for (ValidationContextResourceProxy t : localContext.getResources()) {
|
||||
CodeSystem cs = (CodeSystem) t.loadContainedResource(id, CodeSystem.class);
|
||||
if (cs != null) {
|
||||
localSystems.add(cs);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new Error("Not done yet #2: "+ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ValidationResult validateCode(CodeableConcept code) throws FHIRException {
|
||||
// first, we validate the codings themselves
|
||||
List<String> errors = new ArrayList<String>();
|
||||
|
@ -85,7 +128,7 @@ public class ValueSetCheckerSimple extends ValueSetWorker implements ValueSetChe
|
|||
if (!c.hasSystem()) {
|
||||
warnings.add(context.formatMessage(I18nConstants.CODING_HAS_NO_SYSTEM__CANNOT_VALIDATE));
|
||||
}
|
||||
CodeSystem cs = context.fetchCodeSystem(c.getSystem());
|
||||
CodeSystem cs = resolveCodeSystem(c.getSystem());
|
||||
ValidationResult res = null;
|
||||
if (cs == null || cs.getContent() != CodeSystemContentMode.COMPLETE) {
|
||||
res = context.validateCode(options.noClient(), c, null);
|
||||
|
@ -124,6 +167,19 @@ public class ValueSetCheckerSimple extends ValueSetWorker implements ValueSetChe
|
|||
}
|
||||
}
|
||||
|
||||
public CodeSystem resolveCodeSystem(String system) {
|
||||
for (CodeSystem t : localSystems) {
|
||||
if (t.getUrl().equals(system)) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
CodeSystem cs = context.fetchCodeSystem(system);
|
||||
if (cs == null) {
|
||||
cs = findSpecialCodeSystem(system);
|
||||
}
|
||||
return cs;
|
||||
}
|
||||
|
||||
public ValidationResult validateCode(Coding code) throws FHIRException {
|
||||
String warningMessage = null;
|
||||
// first, we validate the concept itself
|
||||
|
@ -144,10 +200,7 @@ public class ValueSetCheckerSimple extends ValueSetWorker implements ValueSetChe
|
|||
}
|
||||
inExpansion = checkExpansion(code);
|
||||
inInclude = checkInclude(code);
|
||||
CodeSystem cs = context.fetchCodeSystem(system);
|
||||
if (cs == null) {
|
||||
cs = findSpecialCodeSystem(system);
|
||||
}
|
||||
CodeSystem cs = resolveCodeSystem(system);
|
||||
if (cs == null) {
|
||||
warningMessage = "Unable to resolve system "+system;
|
||||
if (!inExpansion) {
|
||||
|
@ -498,7 +551,7 @@ public class ValueSetCheckerSimple extends ValueSetWorker implements ValueSetChe
|
|||
if (vsi.hasFilter()) {
|
||||
return null;
|
||||
}
|
||||
CodeSystem cs = context.fetchCodeSystem(vsi.getSystem());
|
||||
CodeSystem cs = resolveCodeSystem(vsi.getSystem());
|
||||
if (cs == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -604,7 +657,7 @@ public class ValueSetCheckerSimple extends ValueSetWorker implements ValueSetChe
|
|||
if (!system.equals(vsi.getSystem()))
|
||||
return false;
|
||||
// ok, we need the code system
|
||||
CodeSystem cs = context.fetchCodeSystem(system);
|
||||
CodeSystem cs = resolveCodeSystem(system);
|
||||
if (cs == null || (cs.getContent() != CodeSystemContentMode.COMPLETE && cs.getContent() != CodeSystemContentMode.FRAGMENT)) {
|
||||
// make up a transient value set with
|
||||
ValueSet vs = new ValueSet();
|
||||
|
@ -709,7 +762,7 @@ public class ValueSetCheckerSimple extends ValueSetWorker implements ValueSetChe
|
|||
return inner.get(url);
|
||||
}
|
||||
ValueSet vs = context.fetchResource(ValueSet.class, url);
|
||||
ValueSetCheckerSimple vsc = new ValueSetCheckerSimple(options, vs, context);
|
||||
ValueSetCheckerSimple vsc = new ValueSetCheckerSimple(options, vs, context, localContext);
|
||||
inner.put(url, vsc);
|
||||
return vsc;
|
||||
}
|
||||
|
|
|
@ -634,6 +634,9 @@ public class ValueSetExpanderSimple extends ValueSetWorker implements ValueSetEx
|
|||
if (cs.getContent() == CodeSystemContentMode.FRAGMENT) {
|
||||
addFragmentWarning(exp, cs);
|
||||
}
|
||||
if (cs.getContent() == CodeSystemContentMode.EXAMPLE) {
|
||||
addExampleWarning(exp, cs);
|
||||
}
|
||||
}
|
||||
|
||||
if (!inc.getConcept().isEmpty()) {
|
||||
|
@ -645,6 +648,8 @@ public class ValueSetExpanderSimple extends ValueSetWorker implements ValueSetEx
|
|||
if (def == null) {
|
||||
if (cs.getContent() == CodeSystemContentMode.FRAGMENT) {
|
||||
addFragmentWarning(exp, cs);
|
||||
} else if (cs.getContent() == CodeSystemContentMode.EXAMPLE) {
|
||||
addExampleWarning(exp, cs);
|
||||
} else {
|
||||
if (checkCodesWhenExpanding) {
|
||||
throw failTSE("Unable to find code '" + c.getCode() + "' in code system " + cs.getUrl());
|
||||
|
@ -733,12 +738,23 @@ public class ValueSetExpanderSimple extends ValueSetWorker implements ValueSetEx
|
|||
}
|
||||
|
||||
private void addFragmentWarning(ValueSetExpansionComponent exp, CodeSystem cs) {
|
||||
for (Extension ex : cs.getExtensionsByUrl(ToolingExtensions.EXT_EXP_FRAGMENT)) {
|
||||
if (ex.getValue().primitiveValue().equals(cs.getUrl())) {
|
||||
String url = cs.getVersionedUrl();
|
||||
for (ValueSetExpansionParameterComponent p : exp.getParameter()) {
|
||||
if ("fragment".equals(p.getName()) && p.hasValueUriType() && url.equals(p.getValue().primitiveValue())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
exp.addExtension(new Extension(ToolingExtensions.EXT_EXP_FRAGMENT).setValue(new UriType(cs.getUrl())));
|
||||
exp.addParameter().setName("fragment").setValue(new UriType(url));
|
||||
}
|
||||
|
||||
private void addExampleWarning(ValueSetExpansionComponent exp, CodeSystem cs) {
|
||||
String url = cs.getVersionedUrl();
|
||||
for (ValueSetExpansionParameterComponent p : exp.getParameter()) {
|
||||
if ("example".equals(p.getName()) && p.hasValueUriType() && url.equals(p.getValue().primitiveValue())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
exp.addParameter().setName("example").setValue(new UriType(url));
|
||||
}
|
||||
|
||||
private List<ConceptDefinitionDesignationComponent> convertDesignations(List<ConceptReferenceDesignationComponent> list) {
|
||||
|
|
|
@ -48,6 +48,9 @@ import org.hl7.fhir.utilities.Utilities;
|
|||
public class ValueSetUtilities {
|
||||
|
||||
public static ValueSet makeShareable(ValueSet vs) {
|
||||
if (!vs.hasExperimental()) {
|
||||
vs.setExperimental(false);
|
||||
}
|
||||
if (!vs.hasMeta())
|
||||
vs.setMeta(new Meta());
|
||||
for (UriType t : vs.getMeta().getProfile())
|
||||
|
@ -129,9 +132,13 @@ public class ValueSetUtilities {
|
|||
}
|
||||
if (fmm != null) {
|
||||
String sfmm = ToolingExtensions.readStringExtension(vs, ToolingExtensions.EXT_FMM_LEVEL);
|
||||
if (Utilities.noString(sfmm) || Integer.parseInt(sfmm) < Integer.parseInt(fmm))
|
||||
if (Utilities.noString(sfmm) || Integer.parseInt(sfmm) < Integer.parseInt(fmm)) {
|
||||
ToolingExtensions.setIntegerExtension(vs, ToolingExtensions.EXT_FMM_LEVEL, Integer.parseInt(fmm));
|
||||
}
|
||||
if (Integer.parseInt(fmm) <= 1) {
|
||||
vs.setExperimental(true);
|
||||
}
|
||||
}
|
||||
if (vs.hasUserData("cs"))
|
||||
CodeSystemUtilities.markStatus((CodeSystem) vs.getUserData("cs"), wg, status, pckage, fmm, normativeVersion);
|
||||
else if (status == StandardsStatus.NORMATIVE && context != null) {
|
||||
|
|
|
@ -151,13 +151,14 @@ public class TestingUtilities extends BaseTestingUtilities {
|
|||
String result = compareXml(f1, f2);
|
||||
if (result != null && SHOW_DIFF) {
|
||||
String diff = Utilities.path(System.getenv("ProgramFiles"), "WinMerge", "WinMergeU.exe");
|
||||
if (new File(diff).exists()) {
|
||||
List<String> command = new ArrayList<String>();
|
||||
command.add("\"" + diff + "\" \"" + f1 + "\" \"" + f2 + "\"");
|
||||
|
||||
ProcessBuilder builder = new ProcessBuilder(command);
|
||||
builder.directory(new CSFile("c:\\temp"));
|
||||
builder.start();
|
||||
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -171,7 +172,7 @@ public class TestingUtilities extends BaseTestingUtilities {
|
|||
}
|
||||
|
||||
private static String compareElements(String path, Element e1, Element e2) {
|
||||
if (!e1.getNamespaceURI().equals(e2.getNamespaceURI()))
|
||||
if (!namespacesMatch(e1.getNamespaceURI(), e2.getNamespaceURI()))
|
||||
return "Namespaces differ at " + path + ": " + e1.getNamespaceURI() + "/" + e2.getNamespaceURI();
|
||||
if (!e1.getLocalName().equals(e2.getLocalName()))
|
||||
return "Names differ at " + path + ": " + e1.getLocalName() + "/" + e2.getLocalName();
|
||||
|
@ -209,6 +210,10 @@ public class TestingUtilities extends BaseTestingUtilities {
|
|||
return null;
|
||||
}
|
||||
|
||||
private static boolean namespacesMatch(String ns1, String ns2) {
|
||||
return ns1 == null ? ns2 == null : ns1.equals(ns2);
|
||||
}
|
||||
|
||||
private static Object normalise(String text) {
|
||||
String result = text.trim().replace('\r', ' ').replace('\n', ' ').replace('\t', ' ');
|
||||
while (result.contains(" "))
|
||||
|
|
|
@ -5539,7 +5539,7 @@ public class FHIRPathEngine {
|
|||
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_BAD_NAME, expr.getName());
|
||||
}
|
||||
} else if (expr.getKind() == Kind.Group) {
|
||||
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_GROUP);
|
||||
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_GROUP, expr.toString());
|
||||
} else if (expr.getKind() == Kind.Constant) {
|
||||
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_CONST);
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ public class IGHelper {
|
|||
public static final String EXT_MAPPING_CSV = ToolingExtensions.EXT_IGP_MAPPING_CSV;
|
||||
public static final String EXT_BUNDLE = ToolingExtensions.EXT_IGP_BUNDLE;
|
||||
public static final String EXT_RESOURCE_INFO = ToolingExtensions.EXT_IGP_RESOURCE_INFO;
|
||||
public static final String EXT_CONTAINED_RESOURCE_INFO = ToolingExtensions.EXT_IGP_CONTAINED_RESOURCE_INFO;
|
||||
public static final String EXT_PRIVATE_BASE = ToolingExtensions.EXT_PRIVATE_BASE;
|
||||
|
||||
public static String readStringParameter(ImplementationGuideDefinitionComponent ig, String name) {
|
||||
|
|
|
@ -276,7 +276,7 @@ public class NPMPackageGenerator {
|
|||
return "hl7.fhir.r3.core";
|
||||
if (v.startsWith("4.0"))
|
||||
return "hl7.fhir.r4.core";
|
||||
if (v.startsWith("4.1"))
|
||||
if (v.startsWith("4.1") || v.startsWith("4.3"))
|
||||
return "hl7.fhir.r4b.core";
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -230,6 +230,7 @@ public class QuestionnaireBuilder {
|
|||
questionnaire.setPublisher(profile.getPublisher());
|
||||
Questionnaire.QuestionnaireItemComponent item = new Questionnaire.QuestionnaireItemComponent();
|
||||
questionnaire.addItem(item);
|
||||
item.setLinkId("meta");
|
||||
item.getCode().addAll(profile.getKeyword());
|
||||
questionnaire.setId(nextId("qs"));
|
||||
}
|
||||
|
@ -241,6 +242,7 @@ public class QuestionnaireBuilder {
|
|||
response.setStatus(QuestionnaireResponseStatus.INPROGRESS);
|
||||
QuestionnaireResponse.QuestionnaireResponseItemComponent item = new QuestionnaireResponse.QuestionnaireResponseItemComponent();
|
||||
response.addItem(item);
|
||||
item.setLinkId("meta");
|
||||
item.setUserData("object", resource);
|
||||
}
|
||||
|
||||
|
@ -260,9 +262,10 @@ public class QuestionnaireBuilder {
|
|||
display.setType(QuestionnaireItemType.DISPLAY);
|
||||
display.setText(element.getComment());
|
||||
group.addItem(display);
|
||||
display.setLinkId(element.getId()+"-display");
|
||||
}
|
||||
group.setType(QuestionnaireItemType.GROUP);
|
||||
ToolingExtensions.addFlyOver(group, element.getDefinition());
|
||||
ToolingExtensions.addFlyOver(group, element.getDefinition(), element.getId()+"-flyover");
|
||||
group.setRequired(element.getMin() > 0);
|
||||
if (element.getMin() > 0)
|
||||
ToolingExtensions.addMin(group, element.getMin());
|
||||
|
@ -284,10 +287,11 @@ public class QuestionnaireBuilder {
|
|||
nparents.addAll(parents);
|
||||
nparents.add(child);
|
||||
QuestionnaireItemComponent childGroup = group.addItem();
|
||||
childGroup.setLinkId(child.getId()+"-grp");
|
||||
childGroup.setType(QuestionnaireItemType.GROUP);
|
||||
|
||||
List<QuestionnaireResponse.QuestionnaireResponseItemComponent> nResponse = new ArrayList<QuestionnaireResponse.QuestionnaireResponseItemComponent>();
|
||||
processExisting(child.getPath(), answerGroups, nResponse);
|
||||
processExisting(child.getPath(), answerGroups, childGroup, nResponse);
|
||||
// if the element has a type, we add a question. else we add a group on the basis that
|
||||
// it will have children of its own
|
||||
if (child.getType().isEmpty() || isAbstractType(child.getType()))
|
||||
|
@ -334,13 +338,14 @@ public class QuestionnaireBuilder {
|
|||
return path.substring(path.lastIndexOf('.')+1);
|
||||
}
|
||||
|
||||
private void processExisting(String path, List<QuestionnaireResponse.QuestionnaireResponseItemComponent> answerGroups, List<QuestionnaireResponse.QuestionnaireResponseItemComponent> nResponse) throws FHIRException {
|
||||
private void processExisting(String path, List<QuestionnaireResponse.QuestionnaireResponseItemComponent> answerGroups, QuestionnaireItemComponent item, List<QuestionnaireResponse.QuestionnaireResponseItemComponent> nResponse) throws FHIRException {
|
||||
// processing existing data
|
||||
for (QuestionnaireResponse.QuestionnaireResponseItemComponent ag : answerGroups) {
|
||||
List<Base> children = ((Element) ag.getUserData("object")).listChildrenByName(tail(path));
|
||||
for (Base child : children) {
|
||||
if (child != null) {
|
||||
QuestionnaireResponse.QuestionnaireResponseItemComponent ans = ag.addItem();
|
||||
ag.setLinkId(item.getLinkId());
|
||||
ans.setUserData("object", child);
|
||||
nResponse.add(ans);
|
||||
}
|
||||
|
@ -366,9 +371,9 @@ public class QuestionnaireBuilder {
|
|||
}
|
||||
|
||||
if (!Utilities.noString(element.getComment()))
|
||||
ToolingExtensions.addFlyOver(group, element.getDefinition()+" "+element.getComment());
|
||||
ToolingExtensions.addFlyOver(group, element.getDefinition()+" "+element.getComment(), group.getLinkId()+"-flyover");
|
||||
else
|
||||
ToolingExtensions.addFlyOver(group, element.getDefinition());
|
||||
ToolingExtensions.addFlyOver(group, element.getDefinition(), group.getLinkId()+"-flyover");
|
||||
|
||||
if (element.getType().size() > 1 || element.getType().get(0).getWorkingCode().equals("*")) {
|
||||
List<TypeRefComponent> types = expandTypeList(element.getType());
|
||||
|
|
|
@ -69,7 +69,9 @@ import java.util.Map;
|
|||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.fhir.ucum.Utilities;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r5.model.Base;
|
||||
import org.hl7.fhir.r5.model.BooleanType;
|
||||
import org.hl7.fhir.r5.model.CanonicalResource;
|
||||
import org.hl7.fhir.r5.model.CanonicalType;
|
||||
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
|
||||
import org.hl7.fhir.r5.model.CodeType;
|
||||
|
@ -89,6 +91,7 @@ import org.hl7.fhir.r5.model.IntegerType;
|
|||
import org.hl7.fhir.r5.model.MarkdownType;
|
||||
import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent;
|
||||
import org.hl7.fhir.r5.model.PrimitiveType;
|
||||
import org.hl7.fhir.r5.model.Property;
|
||||
import org.hl7.fhir.r5.model.Questionnaire.QuestionnaireItemComponent;
|
||||
import org.hl7.fhir.r5.model.Questionnaire.QuestionnaireItemType;
|
||||
import org.hl7.fhir.r5.model.StringType;
|
||||
|
@ -166,6 +169,7 @@ public class ToolingExtensions {
|
|||
public static final String EXT_IGP_MAPPING_CSV = "http://hl7.org/fhir/StructureDefinition/igpublisher-mapping-csv";
|
||||
public static final String EXT_IGP_BUNDLE = "http://hl7.org/fhir/StructureDefinition/igpublisher-bundle";
|
||||
public static final String EXT_IGP_RESOURCE_INFO = "http://hl7.org/fhir/tools/StructureDefinition/resource-information";
|
||||
public static final String EXT_IGP_CONTAINED_RESOURCE_INFO = "http://hl7.org/fhir/tools/StructureDefinition/contained-resource-information";
|
||||
public static final String EXT_IGP_LOADVERSION = "http://hl7.org/fhir/StructureDefinition/igpublisher-loadversion";
|
||||
public static final String EXT_MAX_VALUESET = "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet";
|
||||
public static final String EXT_MIN_VALUESET = "http://hl7.org/fhir/StructureDefinition/elementdefinition-minValueSet";
|
||||
|
@ -182,7 +186,6 @@ public class ToolingExtensions {
|
|||
public static final String EXT_XML_TYPE = "http://hl7.org/fhir/StructureDefinition/structuredefinition-xml-type";
|
||||
public static final String EXT_RENDERED_VALUE = "http://hl7.org/fhir/StructureDefinition/rendered-value";
|
||||
public static final String EXT_OLD_CONCEPTMAP_EQUIVALENCE = "http://hl7.org/fhir/1.0/StructureDefinition/extension-ConceptMap.element.target.equivalence";
|
||||
public static final String EXT_EXP_FRAGMENT = "http://hl7.org/fhir/tools/StructureDefinition/expansion-codesystem-fragment";
|
||||
public static final String EXT_EXP_TOOCOSTLY = "http://hl7.org/fhir/StructureDefinition/valueset-toocostly";
|
||||
public static final String EXT_MUST_SUPPORT = "http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support";
|
||||
public static final String EXT_TRANSLATABLE = "http://hl7.org/fhir/StructureDefinition/elementdefinition-translatable";
|
||||
|
@ -192,6 +195,9 @@ public class ToolingExtensions {
|
|||
public static final String EXT_XML_NAME = "http://hl7.org/fhir/StructureDefinition/elementdefinition-xml-name";
|
||||
public static final String EXT_BINDING_STYLE = "http://hl7.org/fhir/StructureDefinition/elementdefinition-binding-style";
|
||||
public static final String EXT_BINARY_FORMAT = "http://hl7.org/fhir/StructureDefinition/implementationguide-resource-format";
|
||||
public static final String EXT_TARGET_ID = "http://hl7.org/fhir/StructureDefinition/targetElement";
|
||||
public static final String EXT_TARGET_PATH = "http://hl7.org/fhir/StructureDefinition/targetPath";
|
||||
public static final String EXT_VALUESET_SYSTEM = "http://hl7.org/fhir/StructureDefinition/valueset-system";
|
||||
|
||||
// specific extension helpers
|
||||
|
||||
|
@ -462,11 +468,12 @@ public class ToolingExtensions {
|
|||
// return findBooleanExtension(c, EXT_DEPRECATED);
|
||||
// }
|
||||
|
||||
public static void addFlyOver(QuestionnaireItemComponent item, String text){
|
||||
public static void addFlyOver(QuestionnaireItemComponent item, String text, String linkId){
|
||||
if (!StringUtils.isBlank(text)) {
|
||||
QuestionnaireItemComponent display = item.addItem();
|
||||
display.setType(QuestionnaireItemType.DISPLAY);
|
||||
display.setText(text);
|
||||
display.setLinkId(linkId);
|
||||
display.getExtension().add(Factory.newExtension(EXT_CONTROL, Factory.newCodeableConcept("flyover", "http://hl7.org/fhir/questionnaire-item-control", "Fly-over"), true));
|
||||
}
|
||||
}
|
||||
|
@ -900,5 +907,25 @@ public class ToolingExtensions {
|
|||
dr.getExtension().add(Factory.newExtension(url, new UriType(value), true));
|
||||
}
|
||||
|
||||
public static boolean usesExtension(String url, Base base) {
|
||||
if ("Extension".equals(base.fhirType())) {
|
||||
Property p = base.getNamedProperty("url");
|
||||
for (Base b : p.getValues()) {
|
||||
if (url.equals(b.primitiveValue())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Property p : base.children() ) {
|
||||
for (Base v : p.getValues()) {
|
||||
if (usesExtension(url, v)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -35,6 +35,8 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.VersionUtilities;
|
||||
import org.hl7.fhir.utilities.VersionUtilities.VersionURLInfo;
|
||||
|
||||
|
||||
public class TypesUtilities {
|
||||
|
@ -111,7 +113,7 @@ public class TypesUtilities {
|
|||
res.add(new WildcardInformation("id", TypeClassification.PRIMITIVE));
|
||||
res.add(new WildcardInformation("instant", TypeClassification.PRIMITIVE));
|
||||
res.add(new WildcardInformation("integer", TypeClassification.PRIMITIVE));
|
||||
if (!version.startsWith("4.1")) {
|
||||
if (!VersionUtilities.isR4BVer(version)) {
|
||||
res.add(new WildcardInformation("integer64", TypeClassification.PRIMITIVE));
|
||||
}
|
||||
res.add(new WildcardInformation("markdown", TypeClassification.PRIMITIVE));
|
||||
|
@ -130,6 +132,7 @@ public class TypesUtilities {
|
|||
res.add(new WildcardInformation("Annotation", TypeClassification.DATATYPE));
|
||||
res.add(new WildcardInformation("Attachment", TypeClassification.DATATYPE));
|
||||
res.add(new WildcardInformation("CodeableConcept", TypeClassification.DATATYPE));
|
||||
res.add(new WildcardInformation("CodeableReference", TypeClassification.DATATYPE));
|
||||
res.add(new WildcardInformation("Coding", TypeClassification.DATATYPE));
|
||||
res.add(new WildcardInformation("ContactPoint", TypeClassification.DATATYPE));
|
||||
res.add(new WildcardInformation("Count", TypeClassification.DATATYPE));
|
||||
|
@ -142,6 +145,7 @@ public class TypesUtilities {
|
|||
res.add(new WildcardInformation("Quantity", TypeClassification.DATATYPE));
|
||||
res.add(new WildcardInformation("Range", TypeClassification.DATATYPE));
|
||||
res.add(new WildcardInformation("Ratio", TypeClassification.DATATYPE));
|
||||
res.add(new WildcardInformation("RatioRange", TypeClassification.DATATYPE));
|
||||
res.add(new WildcardInformation("Reference", " - a reference to another resource", TypeClassification.DATATYPE));
|
||||
res.add(new WildcardInformation("SampledData", TypeClassification.DATATYPE));
|
||||
res.add(new WildcardInformation("Signature", TypeClassification.DATATYPE));
|
||||
|
|
|
@ -40,7 +40,15 @@ public class XVerExtensionManager {
|
|||
this.context = context;
|
||||
}
|
||||
|
||||
public boolean isR5(String url) {
|
||||
String v = url.substring(20, 23);
|
||||
return "5.0".equals(v);
|
||||
}
|
||||
|
||||
public XVerExtensionStatus status(String url) throws FHIRException {
|
||||
if (url.length() < 24) {
|
||||
return XVerExtensionStatus.Invalid;
|
||||
}
|
||||
String v = url.substring(20, 23);
|
||||
if ("5.0".equals(v)) {
|
||||
v = "4.6"; // for now
|
||||
|
@ -125,6 +133,11 @@ public class XVerExtensionManager {
|
|||
} else {
|
||||
throw new FHIRException("Internal error - attempt to define extension for "+url+" when it is invalid");
|
||||
}
|
||||
if (path.has("modifier") && path.get("modifier").getAsBoolean()) {
|
||||
ElementDefinition baseDef = new ElementDefinition("Extension");
|
||||
sd.getDifferential().getElement().add(0, baseDef);
|
||||
baseDef.setIsModifier(true);
|
||||
}
|
||||
return sd;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ import okhttp3.Headers;
|
|||
import okhttp3.MediaType;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.logging.HttpLoggingInterceptor;
|
||||
import org.hl7.fhir.r5.model.Bundle;
|
||||
import org.hl7.fhir.r5.model.Resource;
|
||||
import org.hl7.fhir.r5.utils.client.EFhirClientException;
|
||||
|
|
|
@ -2,8 +2,8 @@ package org.hl7.fhir.r5.utils.client.network;
|
|||
|
||||
import okhttp3.*;
|
||||
import org.hl7.fhir.utilities.ToolingClientLogger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -22,9 +22,8 @@ public class FhirLoggingInterceptor implements Interceptor {
|
|||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Response intercept(@NotNull Interceptor.Chain chain) throws IOException {
|
||||
public Response intercept(@Nonnull Interceptor.Chain chain) throws IOException {
|
||||
// Log Request
|
||||
Request request = chain.request();
|
||||
logger.logRequest(request.method(), request.url().toString(), new ArrayList<>(request.headers().names()),
|
||||
|
|
|
@ -35,8 +35,8 @@ public class RetryInterceptor implements Interceptor {
|
|||
try {
|
||||
// If we are retrying a failed request that failed due to a bad response from the server, we must close it first
|
||||
if (response != null) {
|
||||
System.out.println("Previous " + chain.request().method() + " attempt returned HTTP<" + (response.code())
|
||||
+ "> from url -> " + chain.request().url() + ".");
|
||||
// System.out.println("Previous " + chain.request().method() + " attempt returned HTTP<" + (response.code())
|
||||
// + "> from url -> " + chain.request().url() + ".");
|
||||
response.close();
|
||||
}
|
||||
// System.out.println(chain.request().method() + " attempt <" + (retryCounter + 1) + "> to url -> " + chain.request().url());
|
||||
|
|
|
@ -9,7 +9,7 @@ import org.hl7.fhir.r5.model.Resource;
|
|||
import org.hl7.fhir.r5.model.TypeDetails;
|
||||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
import org.hl7.fhir.r5.utils.FHIRPathEngine;
|
||||
import org.hl7.fhir.r5.utils.IResourceValidator;
|
||||
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
package org.hl7.fhir.r5.utils.validation;
|
||||
|
||||
public class BundleValidationRule {
|
||||
private String rule;
|
||||
private String profile;
|
||||
private boolean checked;
|
||||
|
||||
public BundleValidationRule(String rule, String profile) {
|
||||
super();
|
||||
this.rule = rule;
|
||||
this.profile = profile;
|
||||
}
|
||||
|
||||
public String getRule() {
|
||||
return rule;
|
||||
}
|
||||
|
||||
public String getProfile() {
|
||||
return profile;
|
||||
}
|
||||
|
||||
public boolean isChecked() {
|
||||
return checked;
|
||||
}
|
||||
|
||||
public void setChecked(boolean checked) {
|
||||
this.checked = checked;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package org.hl7.fhir.r5.utils;
|
||||
package org.hl7.fhir.r5.utils.validation;
|
||||
|
||||
/*
|
||||
Copyright (c) 2011+, HL7, Inc.
|
||||
|
@ -30,26 +30,18 @@ package org.hl7.fhir.r5.utils;
|
|||
*/
|
||||
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
import org.hl7.fhir.r5.utils.validation.constants.BestPracticeWarningLevel;
|
||||
import org.hl7.fhir.r5.utils.validation.constants.CheckDisplayOption;
|
||||
import org.hl7.fhir.r5.utils.validation.constants.IdStatus;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
|
||||
import org.hl7.fhir.r5.model.CanonicalResource;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
import org.hl7.fhir.r5.utils.IResourceValidator.BundleValidationRule;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
/**
|
||||
* Interface to the instance validator. This takes a resource, in one of many forms, and
|
||||
|
@ -60,124 +52,21 @@ import com.google.gson.JsonObject;
|
|||
*/
|
||||
public interface IResourceValidator {
|
||||
|
||||
public class BundleValidationRule {
|
||||
private String rule;
|
||||
private String profile;
|
||||
private boolean checked;
|
||||
|
||||
public BundleValidationRule(String rule, String profile) {
|
||||
super();
|
||||
this.rule = rule;
|
||||
this.profile = profile;
|
||||
}
|
||||
public String getRule() {
|
||||
return rule;
|
||||
}
|
||||
public String getProfile() {
|
||||
return profile;
|
||||
}
|
||||
public boolean isChecked() {
|
||||
return checked;
|
||||
}
|
||||
public void setChecked(boolean checked) {
|
||||
this.checked = checked;
|
||||
}
|
||||
}
|
||||
|
||||
public enum ReferenceValidationPolicy {
|
||||
IGNORE, CHECK_TYPE_IF_EXISTS, CHECK_EXISTS, CHECK_EXISTS_AND_TYPE, CHECK_VALID;
|
||||
|
||||
public boolean checkExists() {
|
||||
return this == CHECK_EXISTS_AND_TYPE || this == CHECK_EXISTS || this == CHECK_VALID || this == CHECK_TYPE_IF_EXISTS;
|
||||
}
|
||||
|
||||
public boolean checkType() {
|
||||
return this == CHECK_TYPE_IF_EXISTS || this == CHECK_EXISTS_AND_TYPE || this == CHECK_VALID;
|
||||
}
|
||||
|
||||
public boolean checkValid() {
|
||||
return this == CHECK_VALID;
|
||||
}
|
||||
}
|
||||
|
||||
public interface IValidationProfileUsageTracker {
|
||||
void recordProfileUsage(StructureDefinition profile, Object appContext, Element element);
|
||||
}
|
||||
|
||||
|
||||
public interface IValidatorResourceFetcher {
|
||||
|
||||
Element fetch(IResourceValidator validator, Object appContext, String url) throws FHIRFormatError, DefinitionException, FHIRException, IOException;
|
||||
ReferenceValidationPolicy validationPolicy(IResourceValidator validator, Object appContext, String path, String url);
|
||||
boolean resolveURL(IResourceValidator validator, Object appContext, String path, String url, String type) throws IOException, FHIRException;
|
||||
|
||||
byte[] fetchRaw(IResourceValidator validator, String url) throws MalformedURLException, IOException; // for attachment checking
|
||||
|
||||
IValidatorResourceFetcher setLocale(Locale locale);
|
||||
|
||||
|
||||
/**
|
||||
* this is used when the validator encounters a reference to a structure definition, value set or code system at some random URL reference
|
||||
* while validating.
|
||||
*
|
||||
* Added in v5.2.2. return null to leave functionality as it was before then.
|
||||
*
|
||||
* @param primitiveValue
|
||||
* @return an R5 version of the resource
|
||||
* @throws URISyntaxException
|
||||
*/
|
||||
CanonicalResource fetchCanonicalResource(IResourceValidator validator, String url) throws URISyntaxException;
|
||||
|
||||
/**
|
||||
* Whether to try calling fetchCanonicalResource for this reference (not whether it will succeed - just throw an exception from fetchCanonicalResource if it doesn't resolve. This is a policy thing.
|
||||
*
|
||||
* Added in v5.2.2. return false to leave functionality as it was before then.
|
||||
*
|
||||
* @param url
|
||||
* @return
|
||||
*/
|
||||
boolean fetchesCanonicalResource(IResourceValidator validator, String url);
|
||||
}
|
||||
|
||||
public enum BestPracticeWarningLevel {
|
||||
Ignore,
|
||||
Hint,
|
||||
Warning,
|
||||
Error
|
||||
}
|
||||
|
||||
public enum CheckDisplayOption {
|
||||
Ignore,
|
||||
Check,
|
||||
CheckCaseAndSpace,
|
||||
CheckCase,
|
||||
CheckSpace
|
||||
}
|
||||
|
||||
enum IdStatus {
|
||||
OPTIONAL, REQUIRED, PROHIBITED
|
||||
}
|
||||
|
||||
/**
|
||||
* how much to check displays for coded elements
|
||||
* @return
|
||||
*/
|
||||
CheckDisplayOption getCheckDisplay();
|
||||
void setCheckDisplay(CheckDisplayOption checkDisplay);
|
||||
|
||||
/**
|
||||
* whether the resource must have an id or not (depends on context)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
|
||||
IdStatus getResourceIdRule();
|
||||
void setResourceIdRule(IdStatus resourceIdRule);
|
||||
|
||||
/**
|
||||
* whether the validator should enforce best practice guidelines
|
||||
* as defined by various HL7 committees
|
||||
*
|
||||
*/
|
||||
BestPracticeWarningLevel getBestPracticeWarningLevel();
|
||||
IResourceValidator setBestPracticeWarningLevel(BestPracticeWarningLevel value);
|
||||
|
@ -185,48 +74,46 @@ public interface IResourceValidator {
|
|||
IValidatorResourceFetcher getFetcher();
|
||||
IResourceValidator setFetcher(IValidatorResourceFetcher value);
|
||||
|
||||
IValidationPolicyAdvisor getPolicyAdvisor();
|
||||
IResourceValidator setPolicyAdvisor(IValidationPolicyAdvisor advisor);
|
||||
|
||||
IValidationProfileUsageTracker getTracker();
|
||||
IResourceValidator setTracker(IValidationProfileUsageTracker value);
|
||||
|
||||
boolean isNoBindingMsgSuppressed();
|
||||
IResourceValidator setNoBindingMsgSuppressed(boolean noBindingMsgSuppressed);
|
||||
|
||||
public boolean isNoInvariantChecks();
|
||||
public IResourceValidator setNoInvariantChecks(boolean value) ;
|
||||
boolean isNoInvariantChecks();
|
||||
IResourceValidator setNoInvariantChecks(boolean value) ;
|
||||
|
||||
public boolean isWantInvariantInMessage();
|
||||
public IResourceValidator setWantInvariantInMessage(boolean wantInvariantInMessage);
|
||||
boolean isWantInvariantInMessage();
|
||||
IResourceValidator setWantInvariantInMessage(boolean wantInvariantInMessage);
|
||||
|
||||
public boolean isNoTerminologyChecks();
|
||||
public IResourceValidator setNoTerminologyChecks(boolean noTerminologyChecks);
|
||||
boolean isNoTerminologyChecks();
|
||||
IResourceValidator setNoTerminologyChecks(boolean noTerminologyChecks);
|
||||
|
||||
public boolean isNoExtensibleWarnings();
|
||||
public IResourceValidator setNoExtensibleWarnings(boolean noExtensibleWarnings);
|
||||
boolean isNoExtensibleWarnings();
|
||||
IResourceValidator setNoExtensibleWarnings(boolean noExtensibleWarnings);
|
||||
|
||||
public boolean isNoUnicodeBiDiControlChars();
|
||||
public void setNoUnicodeBiDiControlChars(boolean noUnicodeBiDiControlChars);
|
||||
boolean isNoUnicodeBiDiControlChars();
|
||||
void setNoUnicodeBiDiControlChars(boolean noUnicodeBiDiControlChars);
|
||||
|
||||
/**
|
||||
* Whether being unable to resolve a profile in found in Resource.meta.profile or ElementDefinition.type.profile or targetProfile is an error or just a warning
|
||||
* @return
|
||||
*/
|
||||
public boolean isErrorForUnknownProfiles();
|
||||
public void setErrorForUnknownProfiles(boolean errorForUnknownProfiles);
|
||||
boolean isErrorForUnknownProfiles();
|
||||
void setErrorForUnknownProfiles(boolean errorForUnknownProfiles);
|
||||
|
||||
public boolean isShowMessagesFromReferences();
|
||||
public void setShowMessagesFromReferences(boolean value);
|
||||
boolean isShowMessagesFromReferences();
|
||||
void setShowMessagesFromReferences(boolean value);
|
||||
|
||||
/**
|
||||
* this is used internally in the publishing stack to ensure that everything is water tight, but
|
||||
* this check is not necessary or appropriate at run time when the validator is hosted in HAPI
|
||||
* @return
|
||||
*/
|
||||
public boolean isWantCheckSnapshotUnchanged();
|
||||
public void setWantCheckSnapshotUnchanged(boolean wantCheckSnapshotUnchanged);
|
||||
|
||||
//FIXME: don't need that, gets never used?
|
||||
// public String getValidationLanguage();
|
||||
// public void setValidationLanguage(String value);
|
||||
boolean isWantCheckSnapshotUnchanged();
|
||||
void setWantCheckSnapshotUnchanged(boolean wantCheckSnapshotUnchanged);
|
||||
|
||||
/**
|
||||
* It's common to see references such as Patient/234234 - these usually mean a reference to a Patient resource.
|
||||
|
@ -235,27 +122,28 @@ public interface IResourceValidator {
|
|||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isAssumeValidRestReferences();
|
||||
public void setAssumeValidRestReferences(boolean value);
|
||||
boolean isAssumeValidRestReferences();
|
||||
void setAssumeValidRestReferences(boolean value);
|
||||
|
||||
/**
|
||||
* if this is true, the validator will accept extensions and references to example.org and acme.com as
|
||||
* valid, on the basis that they are understood to be references to content that could exist in priniple but can't in practice
|
||||
*/
|
||||
public boolean isAllowExamples();
|
||||
public void setAllowExamples(boolean value) ;
|
||||
boolean isAllowExamples();
|
||||
void setAllowExamples(boolean value) ;
|
||||
|
||||
boolean isNoCheckAggregation();
|
||||
void setNoCheckAggregation(boolean value);
|
||||
|
||||
public boolean isNoCheckAggregation();
|
||||
public void setNoCheckAggregation(boolean value);
|
||||
/**
|
||||
* CrumbTrail - whether the validator creates hints to
|
||||
* @return
|
||||
*/
|
||||
public boolean isCrumbTrails();
|
||||
public void setCrumbTrails(boolean crumbTrails);
|
||||
boolean isCrumbTrails();
|
||||
void setCrumbTrails(boolean crumbTrails);
|
||||
|
||||
public boolean isValidateValueSetCodesOnTxServer();
|
||||
public void setValidateValueSetCodesOnTxServer(boolean value);
|
||||
boolean isValidateValueSetCodesOnTxServer();
|
||||
void setValidateValueSetCodesOnTxServer(boolean value);
|
||||
|
||||
/**
|
||||
* Bundle validation rules allow for requesting particular entries in a bundle get validated against particular profiles
|
||||
|
@ -264,7 +152,7 @@ public interface IResourceValidator {
|
|||
*
|
||||
* @return
|
||||
*/
|
||||
public List<BundleValidationRule> getBundleValidationRules();
|
||||
List<BundleValidationRule> getBundleValidationRules();
|
||||
|
||||
/**
|
||||
* Validate suite
|
|
@ -0,0 +1,82 @@
|
|||
package org.hl7.fhir.r5.utils.validation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
import org.hl7.fhir.r5.model.ElementDefinition;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
import org.hl7.fhir.r5.utils.validation.constants.ContainedReferenceValidationPolicy;
|
||||
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
|
||||
import org.hl7.fhir.r5.utils.validation.constants.CodedContentValidationPolicy;
|
||||
import org.hl7.fhir.r5.utils.validation.constants.BindingKind;
|
||||
|
||||
public interface IValidationPolicyAdvisor {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param validator
|
||||
* @param appContext What was originally provided from the app for it's context
|
||||
* @param path Path that led us to this resource.
|
||||
* @param url Url of the profile the container resource is being validated against.
|
||||
* @return {@link ReferenceValidationPolicy}
|
||||
*/
|
||||
ReferenceValidationPolicy policyForReference(IResourceValidator validator,
|
||||
Object appContext,
|
||||
String path,
|
||||
String url);
|
||||
|
||||
/**
|
||||
* //TODO pass through the actual containing Element as opposed to the type, id
|
||||
* @param validator
|
||||
* @param appContext What was originally provided from the app for it's context
|
||||
* @param containerType Type of the resources that contains the resource being validated
|
||||
* @param containerId Id of the resources that contains the resource being validated
|
||||
* @param containingResourceType Type of the resource that will be validated (BUNDLE_ENTRY, BUNDLE_OUTCOME, CONTAINED_RESOURCE, PARAMETER)
|
||||
* @param path Path that led us to this resource.
|
||||
* @param url Url of the profile the container resource is being validated against.
|
||||
* @return {@link ReferenceValidationPolicy}
|
||||
*/
|
||||
ContainedReferenceValidationPolicy policyForContained(IResourceValidator validator,
|
||||
Object appContext,
|
||||
String containerType,
|
||||
String containerId,
|
||||
Element.SpecialElement containingResourceType,
|
||||
String path,
|
||||
String url);
|
||||
|
||||
/**
|
||||
* Called before validating a concept in an instance against the terminology sub-system
|
||||
*
|
||||
* There's two reasons to use this policy advisor feature:
|
||||
* - save time by not calling the terminology server for validation that don't bring value to the context calling the validation
|
||||
* - suppressing known issues from being listed as a problem
|
||||
*
|
||||
* Note that the terminology subsystem has two parts: a mini-terminology server running inside the
|
||||
* validator, and then calling out to an external terminology service (usually tx.fhir.org, though you
|
||||
* run your own local copy of this - see https://confluence.hl7.org/display/FHIR/Running+your+own+copy+of+tx.fhir.org).
|
||||
* You can't tell which subsystem will handle the terminology validation directly from the content provided here which
|
||||
* subsystem will be called - you'll haev to investigate based on your set up. (matters, since it makes a huge performance
|
||||
* difference, though it also depends on caching, and the impact of caching is also not known at this point)
|
||||
*
|
||||
* @param validator
|
||||
* @param appContext What was originally provided from the app for it's context
|
||||
* @param stackPath The current path for the stack. Note that the because of cross-references and FHIRPath conformsTo() statements, the stack can wind through the content unpredictably.
|
||||
* @param definition the definition being validated against (might be useful: ElementDefinition.base.path, ElementDefinition.type, ElementDefinition.binding
|
||||
* @param structure The structure definition that contains the element definition being validated against (may be from the base spec, may be from a profile)
|
||||
* @param kind The part of the binding being validated
|
||||
* @param valueSet The value set for the binding part that's being validated
|
||||
* @param systems A list of canonical URls (including versions if known) of the systems in the instance that's being validated. Note that if a plain code is being validated, then there'll be no known system when this is called (systems will be empty, not null)
|
||||
* @return {@link CodedContentValidationPolicy}
|
||||
*/
|
||||
CodedContentValidationPolicy policyForCodedContent(IResourceValidator validator,
|
||||
Object appContext,
|
||||
String stackPath,
|
||||
ElementDefinition definition,
|
||||
StructureDefinition structure,
|
||||
BindingKind kind,
|
||||
ValueSet valueSet,
|
||||
List<String> systems);
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package org.hl7.fhir.r5.utils.validation;
|
||||
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
|
||||
public interface IValidationProfileUsageTracker {
|
||||
void recordProfileUsage(StructureDefinition profile, Object appContext, Element element);
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package org.hl7.fhir.r5.utils.validation;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
import org.hl7.fhir.r5.model.CanonicalResource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Locale;
|
||||
|
||||
public interface IValidatorResourceFetcher {
|
||||
|
||||
Element fetch(IResourceValidator validator, Object appContext, String url) throws FHIRException, IOException;
|
||||
|
||||
boolean resolveURL(IResourceValidator validator, Object appContext, String path, String url, String type) throws IOException, FHIRException;
|
||||
|
||||
byte[] fetchRaw(IResourceValidator validator, String url) throws IOException; // for attachment checking
|
||||
|
||||
IValidatorResourceFetcher setLocale(Locale locale);
|
||||
|
||||
/**
|
||||
* this is used when the validator encounters a reference to a structure definition, value set or code system at some random URL reference
|
||||
* while validating.
|
||||
* <p>
|
||||
* Added in v5.2.2. return null to leave functionality as it was before then.
|
||||
*
|
||||
* @return an R5 version of the resource
|
||||
* @throws URISyntaxException
|
||||
*/
|
||||
CanonicalResource fetchCanonicalResource(IResourceValidator validator, String url) throws URISyntaxException;
|
||||
|
||||
/**
|
||||
* Whether to try calling fetchCanonicalResource for this reference (not whether it will succeed - just throw an exception from fetchCanonicalResource if it doesn't resolve. This is a policy thing.
|
||||
* <p>
|
||||
* Added in v5.2.2. return false to leave functionality as it was before then.
|
||||
*
|
||||
* @param url
|
||||
* @return
|
||||
*/
|
||||
boolean fetchesCanonicalResource(IResourceValidator validator, String url);
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package org.hl7.fhir.r5.utils.validation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
import org.hl7.fhir.r5.model.DomainResource;
|
||||
import org.hl7.fhir.r5.model.Questionnaire;
|
||||
import org.hl7.fhir.r5.model.Resource;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
|
||||
public class ValidationContextCarrier {
|
||||
/**
|
||||
*
|
||||
* When the validator is calling validateCode, it typically has a partially loaded resource that may provide
|
||||
* additional resources that are relevant to the validation. This is a handle back into the validator context
|
||||
* to ask for the resource to be fully loaded if it becomes relevant. Note that the resource may fail to load
|
||||
* (e.g. if it's part of what's being validated) and if it does, the validator will record the validation
|
||||
* issues before throwing an error
|
||||
*
|
||||
* This is a reference back int
|
||||
*
|
||||
*/
|
||||
public interface IValidationContextResourceLoader {
|
||||
public Resource loadContainedResource(List<ValidationMessage> errors, String path, Element resource, String id, Class<? extends Resource> class1) throws FHIRException;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of resources that provide context - typically, a container resource, and a bundle resource.
|
||||
* iterate these in order looking for contained resources
|
||||
*
|
||||
*/
|
||||
public static class ValidationContextResourceProxy {
|
||||
|
||||
// either a resource
|
||||
private Resource resource;
|
||||
|
||||
|
||||
// or an element and a loader
|
||||
private Element element;
|
||||
private IValidationContextResourceLoader loader;
|
||||
private List<ValidationMessage> errors;
|
||||
private String path;
|
||||
|
||||
public ValidationContextResourceProxy(Resource resource) {
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
public ValidationContextResourceProxy(List<ValidationMessage> errors, String path, Element element, IValidationContextResourceLoader loader) {
|
||||
this.errors = errors;
|
||||
this.path = path;
|
||||
this.element = element;
|
||||
this.loader = loader;
|
||||
}
|
||||
|
||||
public Resource loadContainedResource(String id, Class<? extends Resource> class1) throws FHIRException {
|
||||
if (resource == null) {
|
||||
Resource res = loader.loadContainedResource(errors, path, element, id, class1);
|
||||
return res;
|
||||
} else {
|
||||
if (resource instanceof DomainResource) {
|
||||
for (Resource r : ((DomainResource) resource).getContained()) {
|
||||
if (r.getId().equals(id)) {
|
||||
if (class1.isInstance(r))
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<ValidationContextResourceProxy> resources = new ArrayList<>();
|
||||
|
||||
public List<ValidationContextResourceProxy> getResources() {
|
||||
return resources;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package org.hl7.fhir.r5.utils.validation.constants;
|
||||
|
||||
public enum BestPracticeWarningLevel {
|
||||
Ignore,
|
||||
Hint,
|
||||
Warning,
|
||||
Error
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.hl7.fhir.r5.utils.validation.constants;
|
||||
|
||||
public enum BindingKind {
|
||||
/**
|
||||
* The primary binding e.g. ElementDefinition.binding.valueSet
|
||||
*/
|
||||
PRIMARY,
|
||||
|
||||
/**
|
||||
* The max value set
|
||||
*/
|
||||
MAX_VS;
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package org.hl7.fhir.r5.utils.validation.constants;
|
||||
|
||||
public enum CheckDisplayOption {
|
||||
Ignore,
|
||||
Check,
|
||||
CheckCaseAndSpace,
|
||||
CheckCase,
|
||||
CheckSpace
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package org.hl7.fhir.r5.utils.validation.constants;
|
||||
|
||||
public enum CodedContentValidationPolicy {
|
||||
/**
|
||||
* don't validate the code
|
||||
*/
|
||||
IGNORE,
|
||||
|
||||
/**
|
||||
* validate the code against the underlying code systems
|
||||
*/
|
||||
CODE,
|
||||
|
||||
/**
|
||||
* validate the code against the value set too.
|
||||
* Note that this isn't much faster than just validating the code since
|
||||
* the expensive part is hitting the terminology server (if necessary)
|
||||
* and that has to be done for the code part too
|
||||
*/
|
||||
VALUESET //
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package org.hl7.fhir.r5.utils.validation.constants;
|
||||
|
||||
public enum ContainedReferenceValidationPolicy {
|
||||
IGNORE,
|
||||
CHECK_TYPE,
|
||||
CHECK_VALID;
|
||||
|
||||
public boolean ignore() {
|
||||
return this == IGNORE;
|
||||
}
|
||||
|
||||
public boolean checkType() {
|
||||
return this == CHECK_TYPE || this == CHECK_VALID;
|
||||
}
|
||||
|
||||
public boolean checkValid() {
|
||||
return this == CHECK_VALID;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package org.hl7.fhir.r5.utils.validation.constants;
|
||||
|
||||
public enum IdStatus {
|
||||
OPTIONAL,
|
||||
REQUIRED,
|
||||
PROHIBITED
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package org.hl7.fhir.r5.utils.validation.constants;
|
||||
|
||||
public enum ReferenceValidationPolicy {
|
||||
IGNORE,
|
||||
CHECK_TYPE_IF_EXISTS,
|
||||
CHECK_EXISTS,
|
||||
CHECK_EXISTS_AND_TYPE,
|
||||
CHECK_VALID;
|
||||
|
||||
public boolean ignore() {
|
||||
return this == IGNORE;
|
||||
}
|
||||
|
||||
public boolean checkExists() {
|
||||
return this == CHECK_EXISTS_AND_TYPE || this == CHECK_EXISTS || this == CHECK_VALID || this == CHECK_TYPE_IF_EXISTS;
|
||||
}
|
||||
|
||||
public boolean checkType() {
|
||||
return this == CHECK_TYPE_IF_EXISTS || this == CHECK_EXISTS_AND_TYPE || this == CHECK_VALID;
|
||||
}
|
||||
|
||||
public boolean checkValid() {
|
||||
return this == CHECK_VALID;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue