mirror of
https://github.com/hapifhir/org.hl7.fhir.core.git
synced 2025-03-02 01:19:14 +00:00
Refactoring validator engine (#436)
* Initial commit, tests passing * continuing breaking up massive classes
This commit is contained in:
parent
ab5d8ee118
commit
c422ddc388
@ -48,7 +48,6 @@ public class OIDBasedValueSetImporter {
|
||||
return csver;
|
||||
}
|
||||
|
||||
|
||||
protected ConceptSetComponent getInclude(ValueSet vs, String url, String csver) {
|
||||
for (ConceptSetComponent t : vs.getCompose().getInclude()) {
|
||||
if (csver == null) {
|
||||
@ -66,20 +65,4 @@ public class OIDBasedValueSetImporter {
|
||||
c.setVersion(csver);
|
||||
return c;
|
||||
}
|
||||
|
||||
protected Document loadXml(InputStream fn) throws Exception {
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
|
||||
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
|
||||
factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
|
||||
factory.setXIncludeAware(false);
|
||||
factory.setExpandEntityReferences(false);
|
||||
|
||||
factory.setNamespaceAware(true);
|
||||
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||
return builder.parse(fn);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -837,6 +837,5 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
|
||||
}
|
||||
return xverManager;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,33 +1,33 @@
|
||||
package org.hl7.fhir.r5.utils;
|
||||
|
||||
/*
|
||||
Copyright (c) 2011+, HL7, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of HL7 nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
/*
|
||||
Copyright (c) 2011+, HL7, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of HL7 nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@ -112,8 +112,8 @@ public interface IResourceValidator {
|
||||
boolean resolveURL(Object appContext, String path, String url, String type) throws IOException, FHIRException;
|
||||
|
||||
byte[] fetchRaw(String url) throws MalformedURLException, IOException; // for attachment checking
|
||||
|
||||
void setLocale(Locale locale);
|
||||
|
||||
IValidatorResourceFetcher setLocale(Locale locale);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -146,6 +146,14 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Lombok Until I get Around to Rewriting Everything in Kotlin -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.16</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Test Dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.hl7.fhir.testcases</groupId>
|
||||
|
@ -0,0 +1,661 @@
|
||||
package org.hl7.fhir.validation;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.hl7.fhir.convertors.*;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r5.context.SimpleWorkerContext;
|
||||
import org.hl7.fhir.r5.elementmodel.Manager;
|
||||
import org.hl7.fhir.r5.formats.JsonParser;
|
||||
import org.hl7.fhir.r5.formats.XmlParser;
|
||||
import org.hl7.fhir.r5.model.Constants;
|
||||
import org.hl7.fhir.r5.model.ImplementationGuide;
|
||||
import org.hl7.fhir.r5.model.Resource;
|
||||
import org.hl7.fhir.r5.utils.structuremap.StructureMapUtilities;
|
||||
import org.hl7.fhir.utilities.IniFile;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.VersionUtilities;
|
||||
import org.hl7.fhir.utilities.json.JsonTrackingParser;
|
||||
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
|
||||
import org.hl7.fhir.utilities.npm.NpmPackage;
|
||||
import org.hl7.fhir.utilities.turtle.Turtle;
|
||||
import org.hl7.fhir.validation.cli.utils.Common;
|
||||
import org.hl7.fhir.validation.cli.utils.VersionSourceInformation;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
public class IgLoader {
|
||||
|
||||
private static final String[] IGNORED_EXTENSIONS = {"md", "css", "js", "png", "gif", "jpg", "html", "tgz", "pack", "zip"};
|
||||
private static final String[] EXEMPT_FILES = {"spec.internals", "version.info", "schematron.zip", "package.json"};
|
||||
|
||||
@Getter private final FilesystemPackageCacheManager packageCacheManager;
|
||||
@Getter private final SimpleWorkerContext context;
|
||||
@Getter private final String version;
|
||||
@Getter private final boolean isDebug;
|
||||
|
||||
public IgLoader(FilesystemPackageCacheManager packageCacheManager,
|
||||
SimpleWorkerContext context,
|
||||
String theVersion) {
|
||||
this(packageCacheManager, context, theVersion, false);
|
||||
}
|
||||
|
||||
public IgLoader(FilesystemPackageCacheManager packageCacheManager,
|
||||
SimpleWorkerContext context,
|
||||
String theVersion,
|
||||
boolean isDebug) {
|
||||
this.packageCacheManager = packageCacheManager;
|
||||
this.context = context;
|
||||
this.version = theVersion;
|
||||
this.isDebug = isDebug;
|
||||
}
|
||||
|
||||
public void loadIg(List<ImplementationGuide> igs,
|
||||
Map<String, byte[]> binaries,
|
||||
String src,
|
||||
boolean recursive) throws IOException, FHIRException {
|
||||
NpmPackage npm = src.matches(FilesystemPackageCacheManager.PACKAGE_VERSION_REGEX_OPT) && !new File(src).exists() ? getPackageCacheManager().loadPackage(src, null) : null;
|
||||
if (npm != null) {
|
||||
for (String s : npm.dependencies()) {
|
||||
if (!getContext().getLoadedPackages().contains(s)) {
|
||||
if (!VersionUtilities.isCorePackage(s)) {
|
||||
loadIg(igs, binaries, s, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.print(" Load " + src);
|
||||
if (!src.contains("#")) {
|
||||
System.out.print("#" + npm.version());
|
||||
}
|
||||
int count = getContext().loadFromPackage(npm, ValidatorUtils.loaderForVersion(npm.fhirVersion()));
|
||||
System.out.println(" - " + count + " resources (" + getContext().clock().milestone() + ")");
|
||||
} else {
|
||||
System.out.print(" Load " + src);
|
||||
String canonical = null;
|
||||
int count = 0;
|
||||
Map<String, byte[]> source = loadIgSource(src, recursive, true);
|
||||
String version = Constants.VERSION;
|
||||
if (getVersion() != null) {
|
||||
version = getVersion();
|
||||
}
|
||||
if (source.containsKey("version.info")) {
|
||||
version = readInfoVersion(source.get("version.info"));
|
||||
}
|
||||
for (Map.Entry<String, byte[]> t : source.entrySet()) {
|
||||
String fn = t.getKey();
|
||||
if (!exemptFile(fn)) {
|
||||
Resource r = loadFileWithErrorChecking(version, t, fn);
|
||||
if (r != null) {
|
||||
count++;
|
||||
getContext().cacheResource(r);
|
||||
if (r instanceof ImplementationGuide) {
|
||||
canonical = ((ImplementationGuide) r).getUrl();
|
||||
igs.add((ImplementationGuide) r);
|
||||
if (canonical.contains("/ImplementationGuide/")) {
|
||||
Resource r2 = r.copy();
|
||||
((ImplementationGuide) r2).setUrl(canonical.substring(0, canonical.indexOf("/ImplementationGuide/")));
|
||||
getContext().cacheResource(r2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (canonical != null) {
|
||||
ValidatorUtils.grabNatives(binaries, source, canonical);
|
||||
}
|
||||
System.out.println(" - " + count + " resources (" + getContext().clock().milestone() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
public Content loadContent(String source, String opName, boolean asIg) throws FHIRException, IOException {
|
||||
Map<String, byte[]> s = loadIgSource(source, false, asIg);
|
||||
Content res = new Content();
|
||||
if (s.size() != 1)
|
||||
throw new FHIRException("Unable to find resource " + source + " to " + opName);
|
||||
for (Map.Entry<String, byte[]> t : s.entrySet()) {
|
||||
res.focus = t.getValue();
|
||||
if (t.getKey().endsWith(".json"))
|
||||
res.cntType = Manager.FhirFormat.JSON;
|
||||
else if (t.getKey().endsWith(".xml"))
|
||||
res.cntType = Manager.FhirFormat.XML;
|
||||
else if (t.getKey().endsWith(".ttl"))
|
||||
res.cntType = Manager.FhirFormat.TURTLE;
|
||||
else if (t.getKey().endsWith(".txt") || t.getKey().endsWith(".map"))
|
||||
res.cntType = Manager.FhirFormat.TEXT;
|
||||
else
|
||||
throw new FHIRException("Todo: Determining resource type is not yet done");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* explore should be true if we're trying to load an -ig parameter, and false if we're loading source
|
||||
*
|
||||
* @throws IOException
|
||||
**/
|
||||
public Map<String, byte[]> loadIgSource(String src,
|
||||
boolean recursive,
|
||||
boolean explore) throws FHIRException, IOException {
|
||||
// src can be one of the following:
|
||||
// - a canonical url for an ig - this will be converted to a package id and loaded into the cache
|
||||
// - a package id for an ig - this will be loaded into the cache
|
||||
// - a direct reference to a package ("package.tgz") - this will be extracted by the cache manager, but not put in the cache
|
||||
// - a folder containing resources - these will be loaded directly
|
||||
if (Common.isNetworkPath(src)) {
|
||||
String v = null;
|
||||
if (src.contains("|")) {
|
||||
v = src.substring(src.indexOf("|") + 1);
|
||||
src = src.substring(0, src.indexOf("|"));
|
||||
}
|
||||
String pid = explore ? getPackageCacheManager().getPackageId(src) : null;
|
||||
if (!Utilities.noString(pid))
|
||||
return fetchByPackage(pid + (v == null ? "" : "#" + v));
|
||||
else
|
||||
return fetchFromUrl(src + (v == null ? "" : "|" + v), explore);
|
||||
}
|
||||
|
||||
File f = new File(Utilities.path(src));
|
||||
if (f.exists()) {
|
||||
if (f.isDirectory() && new File(Utilities.path(src, "package.tgz")).exists())
|
||||
return loadPackage(new FileInputStream(Utilities.path(src, "package.tgz")), Utilities.path(src, "package.tgz"));
|
||||
if (f.isDirectory() && new File(Utilities.path(src, "igpack.zip")).exists())
|
||||
return readZip(new FileInputStream(Utilities.path(src, "igpack.zip")));
|
||||
if (f.isDirectory() && new File(Utilities.path(src, "validator.pack")).exists())
|
||||
return readZip(new FileInputStream(Utilities.path(src, "validator.pack")));
|
||||
if (f.isDirectory())
|
||||
return scanDirectory(f, recursive);
|
||||
if (src.endsWith(".tgz"))
|
||||
return loadPackage(new FileInputStream(src), src);
|
||||
if (src.endsWith(".pack"))
|
||||
return readZip(new FileInputStream(src));
|
||||
if (src.endsWith("igpack.zip"))
|
||||
return readZip(new FileInputStream(src));
|
||||
Manager.FhirFormat fmt = ResourceChecker.checkIsResource(getContext(), isDebug(), src);
|
||||
if (fmt != null) {
|
||||
Map<String, byte[]> res = new HashMap<String, byte[]>();
|
||||
res.put(Utilities.changeFileExt(src, "." + fmt.getExtension()), TextFile.fileToBytesNCS(src));
|
||||
return res;
|
||||
}
|
||||
} else if ((src.matches(FilesystemPackageCacheManager.PACKAGE_REGEX) || src.matches(FilesystemPackageCacheManager.PACKAGE_VERSION_REGEX)) && !src.endsWith(".zip") && !src.endsWith(".tgz")) {
|
||||
return fetchByPackage(src);
|
||||
}
|
||||
throw new FHIRException("Unable to find/resolve/read " + (explore ? "-ig " : "") + src);
|
||||
}
|
||||
|
||||
public void scanForIgVersion(String src,
|
||||
boolean recursive,
|
||||
VersionSourceInformation versions) throws Exception {
|
||||
Map<String, byte[]> source = loadIgSourceForVersion(src, recursive, true, versions);
|
||||
if (source != null && source.containsKey("version.info"))
|
||||
versions.see(readInfoVersion(source.get("version.info")), "version.info in " + src);
|
||||
}
|
||||
|
||||
protected Map<String, byte[]> readZip(InputStream stream) throws IOException {
|
||||
Map<String, byte[]> res = new HashMap<>();
|
||||
ZipInputStream zip = new ZipInputStream(stream);
|
||||
ZipEntry ze;
|
||||
while ((ze = zip.getNextEntry()) != null) {
|
||||
String name = ze.getName();
|
||||
ByteArrayOutputStream b = new ByteArrayOutputStream();
|
||||
int n;
|
||||
byte[] buf = new byte[1024];
|
||||
while ((n = ((InputStream) zip).read(buf, 0, 1024)) > -1) {
|
||||
b.write(buf, 0, n);
|
||||
}
|
||||
res.put(name, b.toByteArray());
|
||||
zip.closeEntry();
|
||||
}
|
||||
zip.close();
|
||||
return res;
|
||||
}
|
||||
|
||||
private String loadPackageForVersion(InputStream stream) throws FHIRException, IOException {
|
||||
return NpmPackage.fromPackage(stream).fhirVersion();
|
||||
}
|
||||
|
||||
private InputStream fetchFromUrlSpecific(String source, boolean optional) throws FHIRException, IOException {
|
||||
try {
|
||||
URL url = new URL(source + "?nocache=" + System.currentTimeMillis());
|
||||
URLConnection c = url.openConnection();
|
||||
return c.getInputStream();
|
||||
} catch (IOException e) {
|
||||
if (optional)
|
||||
return null;
|
||||
else
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, byte[]> loadIgSourceForVersion(String src,
|
||||
boolean recursive,
|
||||
boolean explore,
|
||||
VersionSourceInformation versions) throws FHIRException, IOException {
|
||||
if (Common.isNetworkPath(src)) {
|
||||
String v = null;
|
||||
if (src.contains("|")) {
|
||||
v = src.substring(src.indexOf("|") + 1);
|
||||
src = src.substring(0, src.indexOf("|"));
|
||||
}
|
||||
String pid = getPackageCacheManager().getPackageId(src);
|
||||
if (!Utilities.noString(pid)) {
|
||||
versions.see(fetchVersionByPackage(pid + (v == null ? "" : "#" + v)), "Package " + src);
|
||||
return null;
|
||||
} else {
|
||||
return fetchVersionFromUrl(src + (v == null ? "" : "|" + v), explore, versions);
|
||||
}
|
||||
}
|
||||
|
||||
File f = new File(Utilities.path(src));
|
||||
if (f.exists()) {
|
||||
if (f.isDirectory() && new File(Utilities.path(src, "package.tgz")).exists()) {
|
||||
versions.see(loadPackageForVersion(new FileInputStream(Utilities.path(src, "package.tgz"))), "Package " + src);
|
||||
return null;
|
||||
}
|
||||
if (f.isDirectory() && new File(Utilities.path(src, "igpack.zip")).exists())
|
||||
return readZip(new FileInputStream(Utilities.path(src, "igpack.zip")));
|
||||
if (f.isDirectory() && new File(Utilities.path(src, "validator.pack")).exists())
|
||||
return readZip(new FileInputStream(Utilities.path(src, "validator.pack")));
|
||||
if (f.isDirectory())
|
||||
return scanDirectory(f, recursive);
|
||||
if (src.endsWith(".tgz")) {
|
||||
versions.see(loadPackageForVersion(new FileInputStream(src)), "Package " + src);
|
||||
return null;
|
||||
}
|
||||
if (src.endsWith(".pack"))
|
||||
return readZip(new FileInputStream(src));
|
||||
if (src.endsWith("igpack.zip"))
|
||||
return readZip(new FileInputStream(src));
|
||||
Manager.FhirFormat fmt = ResourceChecker.checkIsResource(getContext(), isDebug(), src);
|
||||
if (fmt != null) {
|
||||
Map<String, byte[]> res = new HashMap<String, byte[]>();
|
||||
res.put(Utilities.changeFileExt(src, "." + fmt.getExtension()), TextFile.fileToBytesNCS(src));
|
||||
return res;
|
||||
}
|
||||
} else if ((src.matches(FilesystemPackageCacheManager.PACKAGE_REGEX) || src.matches(FilesystemPackageCacheManager.PACKAGE_VERSION_REGEX)) && !src.endsWith(".zip") && !src.endsWith(".tgz")) {
|
||||
versions.see(fetchVersionByPackage(src), "Package " + src);
|
||||
return null;
|
||||
}
|
||||
throw new FHIRException("Unable to find/resolve/read -ig " + src);
|
||||
}
|
||||
|
||||
|
||||
private Map<String, byte[]> fetchByPackage(String src) throws FHIRException, IOException {
|
||||
String id = src;
|
||||
String version = null;
|
||||
if (src.contains("#")) {
|
||||
id = src.substring(0, src.indexOf("#"));
|
||||
version = src.substring(src.indexOf("#") + 1);
|
||||
}
|
||||
if (version == null) {
|
||||
version = getPackageCacheManager().getLatestVersion(id);
|
||||
}
|
||||
NpmPackage pi;
|
||||
if (version == null) {
|
||||
pi = getPackageCacheManager().loadPackageFromCacheOnly(id);
|
||||
if (pi != null)
|
||||
System.out.println(" ... Using version " + pi.version());
|
||||
} else
|
||||
pi = getPackageCacheManager().loadPackageFromCacheOnly(id, version);
|
||||
if (pi == null) {
|
||||
return resolvePackage(id, version);
|
||||
} else
|
||||
return loadPackage(pi);
|
||||
}
|
||||
|
||||
private Map<String, byte[]> loadPackage(InputStream stream, String name) throws FHIRException, IOException {
|
||||
return loadPackage(NpmPackage.fromPackage(stream));
|
||||
}
|
||||
|
||||
public Map<String, byte[]> loadPackage(NpmPackage pi) throws FHIRException, IOException {
|
||||
getContext().getLoadedPackages().add(pi.name() + "#" + pi.version());
|
||||
Map<String, byte[]> res = new HashMap<String, byte[]>();
|
||||
for (String s : pi.dependencies()) {
|
||||
if (s.endsWith(".x") && s.length() > 2) {
|
||||
String packageMajorMinor = s.substring(0, s.length() - 2);
|
||||
boolean found = false;
|
||||
for (int i = 0; i < getContext().getLoadedPackages().size() && !found; ++i) {
|
||||
String loadedPackage = getContext().getLoadedPackages().get(i);
|
||||
if (loadedPackage.startsWith(packageMajorMinor)) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
continue;
|
||||
}
|
||||
if (!getContext().getLoadedPackages().contains(s)) {
|
||||
if (!VersionUtilities.isCorePackage(s)) {
|
||||
System.out.println("+ .. load IG from " + s);
|
||||
res.putAll(fetchByPackage(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (String s : pi.listResources("CodeSystem", "ConceptMap", "ImplementationGuide", "CapabilityStatement", "SearchParameter", "Conformance", "StructureMap", "ValueSet", "StructureDefinition")) {
|
||||
res.put(s, TextFile.streamToBytes(pi.load("package", s)));
|
||||
}
|
||||
String ini = "[FHIR]\r\nversion=" + pi.fhirVersion() + "\r\n";
|
||||
res.put("version.info", ini.getBytes());
|
||||
return res;
|
||||
}
|
||||
|
||||
private Map<String, byte[]> resolvePackage(String id, String v) throws FHIRException, IOException {
|
||||
NpmPackage pi = getPackageCacheManager().loadPackage(id, v);
|
||||
if (pi != null && v == null)
|
||||
System.out.println(" ... Using version " + pi.version());
|
||||
return loadPackage(pi);
|
||||
}
|
||||
|
||||
private String readInfoVersion(byte[] bs) throws IOException {
|
||||
String is = TextFile.bytesToString(bs);
|
||||
is = is.trim();
|
||||
IniFile ini = new IniFile(new ByteArrayInputStream(TextFile.stringToBytes(is, false)));
|
||||
return ini.getStringProperty("FHIR", "version");
|
||||
}
|
||||
|
||||
private byte[] fetchFromUrlSpecific(String source, String contentType, boolean optional, List<String> errors) throws FHIRException, IOException {
|
||||
try {
|
||||
try {
|
||||
// try with cache-busting option and then try withhout in case the server doesn't support that
|
||||
URL url = new URL(source + "?nocache=" + System.currentTimeMillis());
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
conn.setRequestProperty("Accept", contentType);
|
||||
return TextFile.streamToBytes(conn.getInputStream());
|
||||
} catch (Exception e) {
|
||||
URL url = new URL(source);
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
conn.setRequestProperty("Accept", contentType);
|
||||
return TextFile.streamToBytes(conn.getInputStream());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (errors != null) {
|
||||
errors.add("Error accessing " + source + ": " + e.getMessage());
|
||||
}
|
||||
if (optional)
|
||||
return null;
|
||||
else
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, byte[]> fetchVersionFromUrl(String src,
|
||||
boolean explore,
|
||||
VersionSourceInformation versions) throws FHIRException, IOException {
|
||||
if (src.endsWith(".tgz")) {
|
||||
versions.see(loadPackageForVersion(fetchFromUrlSpecific(src, false)), "From Package " + src);
|
||||
return null;
|
||||
}
|
||||
if (src.endsWith(".pack"))
|
||||
return readZip(fetchFromUrlSpecific(src, false));
|
||||
if (src.endsWith("igpack.zip"))
|
||||
return readZip(fetchFromUrlSpecific(src, false));
|
||||
|
||||
InputStream stream = null;
|
||||
if (explore) {
|
||||
stream = fetchFromUrlSpecific(Utilities.pathURL(src, "package.tgz"), true);
|
||||
if (stream != null) {
|
||||
versions.see(loadPackageForVersion(stream), "From Package at " + src);
|
||||
return null;
|
||||
}
|
||||
// todo: these options are deprecated - remove once all IGs have been rebuilt post R4 technical correction
|
||||
stream = fetchFromUrlSpecific(Utilities.pathURL(src, "igpack.zip"), true);
|
||||
if (stream != null)
|
||||
return readZip(stream);
|
||||
stream = fetchFromUrlSpecific(Utilities.pathURL(src, "validator.pack"), true);
|
||||
if (stream != null)
|
||||
return readZip(stream);
|
||||
stream = fetchFromUrlSpecific(Utilities.pathURL(src, "validator.pack"), true);
|
||||
//// -----
|
||||
}
|
||||
|
||||
// ok, having tried all that... now we'll just try to access it directly
|
||||
byte[] cnt;
|
||||
if (stream == null)
|
||||
cnt = fetchFromUrlSpecific(src, "application/json", true, null);
|
||||
else
|
||||
cnt = TextFile.streamToBytes(stream);
|
||||
|
||||
Manager.FhirFormat fmt = ResourceChecker.checkIsResource(getContext(), isDebug(), cnt, src);
|
||||
if (fmt != null) {
|
||||
Map<String, byte[]> res = new HashMap<String, byte[]>();
|
||||
res.put(Utilities.changeFileExt(src, "." + fmt.getExtension()), cnt);
|
||||
return res;
|
||||
}
|
||||
String fn = Utilities.path("[tmp]", "fetch-resource-error-content.bin");
|
||||
TextFile.bytesToFile(cnt, fn);
|
||||
System.out.println("Error Fetching " + src);
|
||||
System.out.println("Some content was found, saved to " + fn);
|
||||
System.out.println("1st 100 bytes = " + presentForDebugging(cnt));
|
||||
throw new FHIRException("Unable to find/resolve/read " + (explore ? "-ig " : "") + src);
|
||||
}
|
||||
|
||||
private String fetchVersionByPackage(String src) throws FHIRException, IOException {
|
||||
String id = src;
|
||||
String version = null;
|
||||
if (src.contains("#")) {
|
||||
id = src.substring(0, src.indexOf("#"));
|
||||
version = src.substring(src.indexOf("#") + 1);
|
||||
}
|
||||
if (version == null) {
|
||||
version = getPackageCacheManager().getLatestVersion(id);
|
||||
}
|
||||
NpmPackage pi = null;
|
||||
if (version == null) {
|
||||
pi = getPackageCacheManager().loadPackageFromCacheOnly(id);
|
||||
if (pi != null)
|
||||
System.out.println(" ... Using version " + pi.version());
|
||||
} else
|
||||
pi = getPackageCacheManager().loadPackageFromCacheOnly(id, version);
|
||||
if (pi == null) {
|
||||
return resolvePackageForVersion(id, version);
|
||||
} else {
|
||||
return pi.fhirVersion();
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, byte[]> fetchFromUrl(String src, boolean explore) throws FHIRException, IOException {
|
||||
if (src.endsWith(".tgz"))
|
||||
return loadPackage(fetchFromUrlSpecific(src, false), src);
|
||||
if (src.endsWith(".pack"))
|
||||
return readZip(fetchFromUrlSpecific(src, false));
|
||||
if (src.endsWith("igpack.zip"))
|
||||
return readZip(fetchFromUrlSpecific(src, false));
|
||||
|
||||
InputStream stream = null;
|
||||
if (explore) {
|
||||
stream = fetchFromUrlSpecific(Utilities.pathURL(src, "package.tgz"), true);
|
||||
if (stream != null)
|
||||
return loadPackage(stream, Utilities.pathURL(src, "package.tgz"));
|
||||
// todo: these options are deprecated - remove once all IGs have been rebuilt post R4 technical correction
|
||||
stream = fetchFromUrlSpecific(Utilities.pathURL(src, "igpack.zip"), true);
|
||||
if (stream != null)
|
||||
return readZip(stream);
|
||||
stream = fetchFromUrlSpecific(Utilities.pathURL(src, "validator.pack"), true);
|
||||
if (stream != null)
|
||||
return readZip(stream);
|
||||
stream = fetchFromUrlSpecific(Utilities.pathURL(src, "validator.pack"), true);
|
||||
//// -----
|
||||
}
|
||||
|
||||
// ok, having tried all that... now we'll just try to access it directly
|
||||
byte[] cnt;
|
||||
List<String> errors = new ArrayList<>();
|
||||
if (stream != null) {
|
||||
cnt = TextFile.streamToBytes(stream);
|
||||
} else {
|
||||
cnt = fetchFromUrlSpecific(src, "application/json", true, errors);
|
||||
if (cnt == null) {
|
||||
cnt = fetchFromUrlSpecific(src, "application/xml", true, errors);
|
||||
}
|
||||
}
|
||||
if (cnt == null) {
|
||||
throw new FHIRException("Unable to fetch content from " + src + " (" + errors.toString() + ")");
|
||||
|
||||
}
|
||||
Manager.FhirFormat fmt = checkFormat(cnt, src);
|
||||
if (fmt != null) {
|
||||
Map<String, byte[]> res = new HashMap<>();
|
||||
res.put(Utilities.changeFileExt(src, "." + fmt.getExtension()), cnt);
|
||||
return res;
|
||||
}
|
||||
throw new FHIRException("Unable to read content from " + src + ": cannot determine format");
|
||||
}
|
||||
|
||||
private boolean isIgnoreFile(File ff) {
|
||||
if (ff.getName().startsWith(".") || ff.getAbsolutePath().contains(".git")) {
|
||||
return true;
|
||||
}
|
||||
return Utilities.existsInList(Utilities.getFileExtension(ff.getName()).toLowerCase(), IGNORED_EXTENSIONS);
|
||||
}
|
||||
|
||||
private Map<String, byte[]> scanDirectory(File f, boolean recursive) throws IOException {
|
||||
Map<String, byte[]> res = new HashMap<>();
|
||||
for (File ff : f.listFiles()) {
|
||||
if (ff.isDirectory() && recursive) {
|
||||
res.putAll(scanDirectory(ff, true));
|
||||
} else if (!isIgnoreFile(ff)) {
|
||||
Manager.FhirFormat fmt = ResourceChecker.checkIsResource(getContext(), isDebug(), ff.getAbsolutePath());
|
||||
if (fmt != null) {
|
||||
res.put(Utilities.changeFileExt(ff.getName(), "." + fmt.getExtension()), TextFile.fileToBytes(ff.getAbsolutePath()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private String resolvePackageForVersion(String id, String v) throws FHIRException, IOException {
|
||||
NpmPackage pi = getPackageCacheManager().loadPackage(id, v);
|
||||
return pi.fhirVersion();
|
||||
}
|
||||
|
||||
private String presentForDebugging(byte[] cnt) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
for (int i = 0; i < Integer.min(cnt.length, 50); i++) {
|
||||
b.append(Integer.toHexString(cnt[i]));
|
||||
}
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
private Manager.FhirFormat checkFormat(byte[] cnt, String filename) {
|
||||
System.out.println(" ..Detect format for " + filename);
|
||||
try {
|
||||
JsonTrackingParser.parseJson(cnt);
|
||||
return Manager.FhirFormat.JSON;
|
||||
} catch (Exception e) {
|
||||
log("Not JSON: " + e.getMessage());
|
||||
}
|
||||
try {
|
||||
ValidatorUtils.parseXml(cnt);
|
||||
return Manager.FhirFormat.XML;
|
||||
} catch (Exception e) {
|
||||
log("Not XML: " + e.getMessage());
|
||||
}
|
||||
try {
|
||||
new Turtle().parse(TextFile.bytesToString(cnt));
|
||||
return Manager.FhirFormat.TURTLE;
|
||||
} catch (Exception e) {
|
||||
log("Not Turtle: " + e.getMessage());
|
||||
}
|
||||
try {
|
||||
new StructureMapUtilities(getContext(), null, null).parse(TextFile.bytesToString(cnt), null);
|
||||
return Manager.FhirFormat.TEXT;
|
||||
} catch (Exception e) {
|
||||
log("Not Text: " + e.getMessage());
|
||||
}
|
||||
log(" .. not a resource: " + filename);
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean exemptFile(String fn) {
|
||||
return Utilities.existsInList(fn, EXEMPT_FILES);
|
||||
}
|
||||
|
||||
private Resource loadFileWithErrorChecking(String version, Map.Entry<String, byte[]> t, String fn) {
|
||||
log("* load file: " + fn);
|
||||
Resource r = null;
|
||||
try {
|
||||
r = loadResourceByVersion(version, t.getValue(), fn);
|
||||
log(" .. success");
|
||||
} catch (Exception e) {
|
||||
if (!isDebug()) {
|
||||
System.out.print("* load file: " + fn);
|
||||
}
|
||||
System.out.println(" - ignored due to error: " + (e.getMessage() == null ? " (null - NPE)" : e.getMessage()));
|
||||
if (isDebug() || ((e.getMessage() != null && e.getMessage().contains("cannot be cast")))) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
public Resource loadResourceByVersion(String fhirVersion, byte[] content, String fn) throws IOException, FHIRException {
|
||||
Resource r;
|
||||
if (fhirVersion.startsWith("3.0")) {
|
||||
org.hl7.fhir.dstu3.model.Resource res;
|
||||
if (fn.endsWith(".xml") && !fn.endsWith("template.xml"))
|
||||
res = new org.hl7.fhir.dstu3.formats.XmlParser().parse(new ByteArrayInputStream(content));
|
||||
else if (fn.endsWith(".json") && !fn.endsWith("template.json"))
|
||||
res = new org.hl7.fhir.dstu3.formats.JsonParser().parse(new ByteArrayInputStream(content));
|
||||
else if (fn.endsWith(".txt") || fn.endsWith(".map"))
|
||||
res = new org.hl7.fhir.dstu3.utils.StructureMapUtilities(null).parse(new String(content));
|
||||
else
|
||||
throw new FHIRException("Unsupported format for " + fn);
|
||||
r = VersionConvertor_30_50.convertResource(res, false);
|
||||
} else if (fhirVersion.startsWith("4.0")) {
|
||||
org.hl7.fhir.r4.model.Resource res;
|
||||
if (fn.endsWith(".xml") && !fn.endsWith("template.xml"))
|
||||
res = new org.hl7.fhir.r4.formats.XmlParser().parse(new ByteArrayInputStream(content));
|
||||
else if (fn.endsWith(".json") && !fn.endsWith("template.json"))
|
||||
res = new org.hl7.fhir.r4.formats.JsonParser().parse(new ByteArrayInputStream(content));
|
||||
else if (fn.endsWith(".txt") || fn.endsWith(".map"))
|
||||
res = new org.hl7.fhir.r4.utils.StructureMapUtilities(null).parse(new String(content), fn);
|
||||
else
|
||||
throw new FHIRException("Unsupported format for " + fn);
|
||||
r = VersionConvertor_40_50.convertResource(res);
|
||||
} else if (fhirVersion.startsWith("1.4")) {
|
||||
org.hl7.fhir.dstu2016may.model.Resource res;
|
||||
if (fn.endsWith(".xml") && !fn.endsWith("template.xml"))
|
||||
res = new org.hl7.fhir.dstu2016may.formats.XmlParser().parse(new ByteArrayInputStream(content));
|
||||
else if (fn.endsWith(".json") && !fn.endsWith("template.json"))
|
||||
res = new org.hl7.fhir.dstu2016may.formats.JsonParser().parse(new ByteArrayInputStream(content));
|
||||
else
|
||||
throw new FHIRException("Unsupported format for " + fn);
|
||||
r = VersionConvertor_14_50.convertResource(res);
|
||||
} else if (fhirVersion.startsWith("1.0")) {
|
||||
org.hl7.fhir.dstu2.model.Resource res;
|
||||
if (fn.endsWith(".xml") && !fn.endsWith("template.xml"))
|
||||
res = new org.hl7.fhir.dstu2.formats.JsonParser().parse(new ByteArrayInputStream(content));
|
||||
else if (fn.endsWith(".json") && !fn.endsWith("template.json"))
|
||||
res = new org.hl7.fhir.dstu2.formats.JsonParser().parse(new ByteArrayInputStream(content));
|
||||
else
|
||||
throw new FHIRException("Unsupported format for " + fn);
|
||||
VersionConvertorAdvisor50 advisor = new org.hl7.fhir.convertors.misc.IGR2ConvertorAdvisor5();
|
||||
r = VersionConvertor_10_50.convertResource(res, advisor);
|
||||
} else if (fhirVersion.equals(Constants.VERSION) || "current".equals(fhirVersion)) {
|
||||
if (fn.endsWith(".xml") && !fn.endsWith("template.xml"))
|
||||
r = new XmlParser().parse(new ByteArrayInputStream(content));
|
||||
else if (fn.endsWith(".json") && !fn.endsWith("template.json"))
|
||||
r = new JsonParser().parse(new ByteArrayInputStream(content));
|
||||
else if (fn.endsWith(".txt"))
|
||||
r = new StructureMapUtilities(context, null, null).parse(TextFile.bytesToString(content), fn);
|
||||
else if (fn.endsWith(".map"))
|
||||
r = new StructureMapUtilities(null).parse(new String(content), fn);
|
||||
else
|
||||
throw new FHIRException("Unsupported format for " + fn);
|
||||
} else
|
||||
throw new FHIRException("Unsupported version " + fhirVersion);
|
||||
return r;
|
||||
}
|
||||
|
||||
private void log(String s) {
|
||||
if (isDebug()) System.out.println(s);
|
||||
}
|
||||
}
|
@ -1,33 +1,33 @@
|
||||
package org.hl7.fhir.validation;
|
||||
|
||||
/*
|
||||
Copyright (c) 2011+, HL7, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of HL7 nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
/*
|
||||
Copyright (c) 2011+, HL7, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of HL7 nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@ -141,6 +141,7 @@ public class NativeHostServices {
|
||||
}
|
||||
|
||||
private ValidationEngine validator;
|
||||
private IgLoader igLoader;
|
||||
private int validationCount = 0;
|
||||
private int resourceCount = 0;
|
||||
private int convertCount = 0;
|
||||
@ -167,6 +168,7 @@ public class NativeHostServices {
|
||||
public void init(String pack) throws Exception {
|
||||
validator = new ValidationEngine(pack);
|
||||
validator.getContext().setAllowLoadingDuplicates(true);
|
||||
igLoader = new IgLoader(validator.getPcm(), validator.getContext(), validator.getVersion(), validator.isDebug());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -177,7 +179,7 @@ public class NativeHostServices {
|
||||
* @throws Exception
|
||||
*/
|
||||
public void load(String pack) throws Exception {
|
||||
validator.loadIg(pack, false);
|
||||
igLoader.loadIg(validator.getIgs(), validator.getBinaries(), pack, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,67 @@
|
||||
package org.hl7.fhir.validation;
|
||||
|
||||
import org.hl7.fhir.r5.context.SimpleWorkerContext;
|
||||
import org.hl7.fhir.r5.elementmodel.Manager;
|
||||
import org.hl7.fhir.r5.utils.structuremap.StructureMapUtilities;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class ResourceChecker {
|
||||
protected static Manager.FhirFormat checkIsResource(SimpleWorkerContext context, boolean debug, byte[] cnt, String filename) {
|
||||
System.out.println(" ..Detect format for " + filename);
|
||||
try {
|
||||
Manager.parse(context, new ByteArrayInputStream(cnt), Manager.FhirFormat.JSON);
|
||||
return Manager.FhirFormat.JSON;
|
||||
} catch (Exception e) {
|
||||
if (debug) {
|
||||
System.out.println("Not JSON: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
try {
|
||||
ValidatorUtils.parseXml(cnt);
|
||||
return Manager.FhirFormat.XML;
|
||||
} catch (Exception e) {
|
||||
if (debug) {
|
||||
System.out.println("Not XML: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
try {
|
||||
Manager.parse(context, new ByteArrayInputStream(cnt), Manager.FhirFormat.TURTLE);
|
||||
return Manager.FhirFormat.TURTLE;
|
||||
} catch (Exception e) {
|
||||
if (debug) {
|
||||
System.out.println("Not Turtle: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
try {
|
||||
new StructureMapUtilities(context, null, null).parse(TextFile.bytesToString(cnt), null);
|
||||
return Manager.FhirFormat.TEXT;
|
||||
} catch (Exception e) {
|
||||
if (debug) {
|
||||
System.out.println("Not Text: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
if (debug)
|
||||
System.out.println(" .. not a resource: " + filename);
|
||||
return null;
|
||||
}
|
||||
|
||||
protected static Manager.FhirFormat checkIsResource(SimpleWorkerContext context, boolean debug, String path) throws IOException {
|
||||
String ext = Utilities.getFileExtension(path);
|
||||
if (Utilities.existsInList(ext, "xml"))
|
||||
return Manager.FhirFormat.XML;
|
||||
if (Utilities.existsInList(ext, "json"))
|
||||
return Manager.FhirFormat.JSON;
|
||||
if (Utilities.existsInList(ext, "ttl"))
|
||||
return Manager.FhirFormat.TURTLE;
|
||||
if (Utilities.existsInList(ext, "map"))
|
||||
return Manager.FhirFormat.TEXT;
|
||||
if (Utilities.existsInList(ext, "txt"))
|
||||
return Manager.FhirFormat.TEXT;
|
||||
|
||||
return checkIsResource(context, debug, TextFile.fileToBytes(path), path);
|
||||
}
|
||||
}
|
@ -0,0 +1,362 @@
|
||||
package org.hl7.fhir.validation;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r5.context.SimpleWorkerContext;
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
import org.hl7.fhir.r5.model.ImplementationGuide;
|
||||
import org.hl7.fhir.r5.model.OperationOutcome;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
import org.hl7.fhir.r5.renderers.RendererFactory;
|
||||
import org.hl7.fhir.r5.renderers.utils.RenderingContext;
|
||||
import org.hl7.fhir.r5.utils.EOperationOutcome;
|
||||
import org.hl7.fhir.r5.utils.FHIRPathEngine;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlComposer;
|
||||
import org.hl7.fhir.validation.cli.model.ScanOutputItem;
|
||||
import org.hl7.fhir.validation.instance.InstanceValidator;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
public class Scanner {
|
||||
|
||||
private static final int BUFFER_SIZE = 4096;
|
||||
|
||||
@Getter private final SimpleWorkerContext context;
|
||||
@Getter private final InstanceValidator validator;
|
||||
@Getter private final IgLoader igLoader;
|
||||
@Getter private final FHIRPathEngine fhirPathEngine;
|
||||
|
||||
public Scanner(SimpleWorkerContext context, InstanceValidator validator, IgLoader igLoader, FHIRPathEngine fhirPathEngine) {
|
||||
this.context = context;
|
||||
this.validator = validator;
|
||||
this.igLoader = igLoader;
|
||||
this.fhirPathEngine = fhirPathEngine;
|
||||
}
|
||||
|
||||
public void validateScan(String output, List<String> sources) throws Exception {
|
||||
if (Utilities.noString(output))
|
||||
throw new Exception("Output parameter required when scanning");
|
||||
if (!(new File(output).isDirectory()))
|
||||
throw new Exception("Output '" + output + "' must be a directory when scanning");
|
||||
System.out.println(" .. scan " + sources + " against loaded IGs");
|
||||
Set<String> urls = new HashSet<>();
|
||||
for (ImplementationGuide ig : getContext().allImplementationGuides()) {
|
||||
if (ig.getUrl().contains("/ImplementationGuide") && !ig.getUrl().equals("http://hl7.org/fhir/ImplementationGuide/fhir"))
|
||||
urls.add(ig.getUrl());
|
||||
}
|
||||
List<ScanOutputItem> res = validateScan(sources, urls);
|
||||
genScanOutput(output, res);
|
||||
System.out.println("Done. output in " + Utilities.path(output, "scan.html"));
|
||||
}
|
||||
|
||||
protected List<ScanOutputItem> validateScan(List<String> sources, Set<String> guides) throws FHIRException, IOException, EOperationOutcome {
|
||||
List<String> refs = new ArrayList<>();
|
||||
ValidatorUtils.parseSources(sources, refs, getContext());
|
||||
|
||||
List<ScanOutputItem> res = new ArrayList();
|
||||
|
||||
for (String ref : refs) {
|
||||
Content cnt = getIgLoader().loadContent(ref, "validate", false);
|
||||
List<ValidationMessage> messages = new ArrayList<>();
|
||||
Element e = null;
|
||||
try {
|
||||
System.out.println("Validate " + ref);
|
||||
messages.clear();
|
||||
e = getValidator().validate(null, messages, new ByteArrayInputStream(cnt.focus), cnt.cntType);
|
||||
res.add(new ScanOutputItem(ref, null, null, ValidatorUtils.messagesToOutcome(messages, getContext(), getFhirPathEngine())));
|
||||
} catch (Exception ex) {
|
||||
res.add(new ScanOutputItem(ref, null, null, exceptionToOutcome(ex)));
|
||||
}
|
||||
if (e != null) {
|
||||
String rt = e.fhirType();
|
||||
for (String u : guides) {
|
||||
ImplementationGuide ig = getContext().fetchResource(ImplementationGuide.class, u);
|
||||
System.out.println("Check Guide " + ig.getUrl());
|
||||
String canonical = ig.getUrl().contains("/Impl") ? ig.getUrl().substring(0, ig.getUrl().indexOf("/Impl")) : ig.getUrl();
|
||||
String url = getGlobal(ig, rt);
|
||||
if (url != null) {
|
||||
try {
|
||||
System.out.println("Validate " + ref + " against " + ig.getUrl());
|
||||
messages.clear();
|
||||
getValidator().validate(null, messages, new ByteArrayInputStream(cnt.focus), cnt.cntType, url);
|
||||
res.add(new ScanOutputItem(ref, ig, null, ValidatorUtils.messagesToOutcome(messages, getContext(), getFhirPathEngine())));
|
||||
} catch (Exception ex) {
|
||||
res.add(new ScanOutputItem(ref, ig, null, exceptionToOutcome(ex)));
|
||||
}
|
||||
}
|
||||
Set<String> done = new HashSet<>();
|
||||
for (StructureDefinition sd : getContext().allStructures()) {
|
||||
if (!done.contains(sd.getUrl())) {
|
||||
done.add(sd.getUrl());
|
||||
if (sd.getUrl().startsWith(canonical) && rt.equals(sd.getType())) {
|
||||
try {
|
||||
System.out.println("Validate " + ref + " against " + sd.getUrl());
|
||||
messages.clear();
|
||||
validator.validate(null, messages, new ByteArrayInputStream(cnt.focus), cnt.cntType, Collections.singletonList(sd));
|
||||
res.add(new ScanOutputItem(ref, ig, sd, ValidatorUtils.messagesToOutcome(messages, getContext(), getFhirPathEngine())));
|
||||
} catch (Exception ex) {
|
||||
res.add(new ScanOutputItem(ref, ig, sd, exceptionToOutcome(ex)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
protected void genScanOutput(String folder, List<ScanOutputItem> items) throws IOException, FHIRException, EOperationOutcome {
|
||||
String f = Utilities.path(folder, "comparison.zip");
|
||||
download("http://fhir.org/archive/comparison.zip", f);
|
||||
unzip(f, folder);
|
||||
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
items.get(i).setId("c" + i);
|
||||
genScanOutputItem(items.get(i), Utilities.path(folder, items.get(i).getId() + ".html"));
|
||||
}
|
||||
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append("<html>");
|
||||
b.append("<head>");
|
||||
b.append("<title>Implementation Guide Scan</title>");
|
||||
b.append("<link rel=\"stylesheet\" href=\"fhir.css\"/>\r\n");
|
||||
b.append("<style>\r\n");
|
||||
b.append("th \r\n");
|
||||
b.append("{\r\n");
|
||||
b.append(" vertical-align: bottom;\r\n");
|
||||
b.append(" text-align: center;\r\n");
|
||||
b.append("}\r\n");
|
||||
b.append("\r\n");
|
||||
b.append("th span\r\n");
|
||||
b.append("{\r\n");
|
||||
b.append(" -ms-writing-mode: tb-rl;\r\n");
|
||||
b.append(" -webkit-writing-mode: vertical-rl;\r\n");
|
||||
b.append(" writing-mode: vertical-rl;\r\n");
|
||||
b.append(" transform: rotate(180deg);\r\n");
|
||||
b.append(" white-space: nowrap;\r\n");
|
||||
b.append("}\r\n");
|
||||
b.append("</style>\r\n");
|
||||
b.append("</head>");
|
||||
b.append("<body>");
|
||||
b.append("<h2>Implementation Guide Scan</h2>");
|
||||
|
||||
// organise
|
||||
Set<String> refs = new HashSet<>();
|
||||
Set<String> igs = new HashSet<>();
|
||||
Map<String, Set<String>> profiles = new HashMap<>();
|
||||
for (ScanOutputItem item : items) {
|
||||
refs.add(item.getRef());
|
||||
if (item.getIg() != null) {
|
||||
igs.add(item.getIg().getUrl());
|
||||
if (!profiles.containsKey(item.getIg().getUrl())) {
|
||||
profiles.put(item.getIg().getUrl(), new HashSet<>());
|
||||
}
|
||||
if (item.getProfile() != null)
|
||||
profiles.get(item.getIg().getUrl()).add(item.getProfile().getUrl());
|
||||
}
|
||||
}
|
||||
|
||||
b.append("<h2>By reference</h2>\r\n");
|
||||
b.append("<table class=\"grid\">");
|
||||
b.append("<tr><th></th><th></th>");
|
||||
for (String s : sort(igs)) {
|
||||
ImplementationGuide ig = getContext().fetchResource(ImplementationGuide.class, s);
|
||||
b.append("<th colspan=\"" + Integer.toString(profiles.get(s).size() + 1) + "\"><b title=\"" + s + "\">" + ig.present() + "</b></th>");
|
||||
}
|
||||
b.append("</tr>\r\n");
|
||||
b.append("<tr><th><b>Source</b></th><th><span>Core Spec</span></th>");
|
||||
for (String s : sort(igs)) {
|
||||
ImplementationGuide ig = getContext().fetchResource(ImplementationGuide.class, s);
|
||||
b.append("<th><span>Global</span></th>");
|
||||
for (String sp : sort(profiles.get(s))) {
|
||||
StructureDefinition sd = getContext().fetchResource(StructureDefinition.class, sp);
|
||||
b.append("<th><b title=\"" + sp + "\"><span>" + sd.present() + "</span></b></th>");
|
||||
}
|
||||
}
|
||||
b.append("</tr>\r\n");
|
||||
|
||||
for (String s : sort(refs)) {
|
||||
b.append("<tr>");
|
||||
b.append("<td>" + s + "</td>");
|
||||
b.append(genOutcome(items, s, null, null));
|
||||
for (String si : sort(igs)) {
|
||||
ImplementationGuide ig = getContext().fetchResource(ImplementationGuide.class, si);
|
||||
b.append(genOutcome(items, s, si, null));
|
||||
for (String sp : sort(profiles.get(ig.getUrl()))) {
|
||||
b.append(genOutcome(items, s, si, sp));
|
||||
}
|
||||
}
|
||||
b.append("</tr>\r\n");
|
||||
}
|
||||
b.append("</table>\r\n");
|
||||
|
||||
b.append("<h2>By IG</h2>\r\n");
|
||||
b.append("<table class=\"grid\">");
|
||||
b.append("<tr><th></th><th></th>");
|
||||
for (String s : sort(refs)) {
|
||||
b.append("<th><span>" + s + "</span></th>");
|
||||
}
|
||||
b.append("</tr>\r\n");
|
||||
b.append("<tr><td></td><td>Core Spec</td>");
|
||||
for (String s : sort(refs)) {
|
||||
b.append(genOutcome(items, s, null, null));
|
||||
}
|
||||
b.append("</tr>\r\n");
|
||||
for (String si : sort(igs)) {
|
||||
b.append("<tr>");
|
||||
ImplementationGuide ig = getContext().fetchResource(ImplementationGuide.class, si);
|
||||
b.append("<td><b title=\"" + si + "\">" + ig.present() + "</b></td>");
|
||||
b.append("<td>Global</td>");
|
||||
for (String s : sort(refs)) {
|
||||
b.append(genOutcome(items, s, si, null));
|
||||
}
|
||||
b.append("</tr>\r\n");
|
||||
|
||||
for (String sp : sort(profiles.get(ig.getUrl()))) {
|
||||
b.append("<tr>");
|
||||
StructureDefinition sd = getContext().fetchResource(StructureDefinition.class, sp);
|
||||
b.append("<td></td><td><b title=\"" + sp + "\">" + sd.present() + "</b></td>");
|
||||
for (String s : sort(refs)) {
|
||||
b.append(genOutcome(items, s, si, sp));
|
||||
}
|
||||
b.append("</tr>\r\n");
|
||||
}
|
||||
}
|
||||
b.append("</table>\r\n");
|
||||
|
||||
b.append("</body>");
|
||||
b.append("</html>");
|
||||
TextFile.stringToFile(b.toString(), Utilities.path(folder, "scan.html"));
|
||||
}
|
||||
|
||||
protected void genScanOutputItem(ScanOutputItem item, String filename) throws IOException, FHIRException, EOperationOutcome {
|
||||
RenderingContext rc = new RenderingContext(getContext(), null, null, "http://hl7.org/fhir", "", null, RenderingContext.ResourceRendererMode.RESOURCE);
|
||||
rc.setNoSlowLookup(true);
|
||||
RendererFactory.factory(item.getOutcome(), rc).render(item.getOutcome());
|
||||
String s = new XhtmlComposer(XhtmlComposer.HTML).compose(item.getOutcome().getText().getDiv());
|
||||
|
||||
String title = item.getTitle();
|
||||
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append("<html>");
|
||||
b.append("<head>");
|
||||
b.append("<title>" + title + "</title>");
|
||||
b.append("<link rel=\"stylesheet\" href=\"fhir.css\"/>\r\n");
|
||||
b.append("</head>");
|
||||
b.append("<body>");
|
||||
b.append("<h2>" + title + "</h2>");
|
||||
b.append(s);
|
||||
b.append("</body>");
|
||||
b.append("</html>");
|
||||
TextFile.stringToFile(b.toString(), filename);
|
||||
}
|
||||
|
||||
protected String genOutcome(List<ScanOutputItem> items, String src, String ig, String profile) {
|
||||
ScanOutputItem item = null;
|
||||
for (ScanOutputItem t : items) {
|
||||
boolean match = true;
|
||||
if (!t.getRef().equals(src))
|
||||
match = false;
|
||||
if (!((ig == null && t.getIg() == null) || (ig != null && t.getIg() != null && ig.equals(t.getIg().getUrl()))))
|
||||
match = false;
|
||||
if (!((profile == null && t.getProfile() == null) || (profile != null && t.getProfile() != null && profile.equals(t.getProfile().getUrl()))))
|
||||
match = false;
|
||||
if (match) {
|
||||
item = t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (item == null)
|
||||
return "<td></td>";
|
||||
boolean ok = true;
|
||||
for (OperationOutcome.OperationOutcomeIssueComponent iss : item.getOutcome().getIssue()) {
|
||||
if (iss.getSeverity() == OperationOutcome.IssueSeverity.ERROR || iss.getSeverity() == OperationOutcome.IssueSeverity.FATAL) {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (ok)
|
||||
return "<td style=\"background-color: #e6ffe6\"><a href=\"" + item.getId() + ".html\">\u2714</a></td>";
|
||||
else
|
||||
return "<td style=\"background-color: #ffe6e6\"><a href=\"" + item.getId() + ".html\">\u2716</a></td>";
|
||||
}
|
||||
|
||||
protected OperationOutcome exceptionToOutcome(Exception ex) throws IOException, FHIRException, EOperationOutcome {
|
||||
OperationOutcome op = new OperationOutcome();
|
||||
op.addIssue().setCode(OperationOutcome.IssueType.EXCEPTION).setSeverity(OperationOutcome.IssueSeverity.FATAL).getDetails().setText(ex.getMessage());
|
||||
RenderingContext rc = new RenderingContext(getContext(), null, null, "http://hl7.org/fhir", "", null, RenderingContext.ResourceRendererMode.RESOURCE);
|
||||
RendererFactory.factory(op, rc).render(op);
|
||||
return op;
|
||||
}
|
||||
|
||||
protected void download(String address, String filename) throws IOException {
|
||||
URL url = new URL(address);
|
||||
URLConnection c = url.openConnection();
|
||||
InputStream s = c.getInputStream();
|
||||
FileOutputStream f = new FileOutputStream(filename);
|
||||
transfer(s, f, 1024);
|
||||
f.close();
|
||||
}
|
||||
|
||||
protected void transfer(InputStream in, OutputStream out, int buffer) throws IOException {
|
||||
byte[] read = new byte[buffer]; // Your buffer size.
|
||||
while (0 < (buffer = in.read(read)))
|
||||
out.write(read, 0, buffer);
|
||||
}
|
||||
|
||||
protected List<String> sort(Set<String> keys) {
|
||||
return keys.stream().sorted().collect(Collectors.toList());
|
||||
}
|
||||
|
||||
protected void unzip(String zipFilePath, String destDirectory) throws IOException {
|
||||
File destDir = new File(destDirectory);
|
||||
if (!destDir.exists()) {
|
||||
destDir.mkdir();
|
||||
}
|
||||
ZipInputStream zipIn = new ZipInputStream(new FileInputStream(zipFilePath));
|
||||
ZipEntry entry = zipIn.getNextEntry();
|
||||
// iterates over entries in the zip file
|
||||
while (entry != null) {
|
||||
String filePath = destDirectory + File.separator + entry.getName();
|
||||
if (!entry.isDirectory()) {
|
||||
// if the entry is a file, extracts it
|
||||
extractFile(zipIn, filePath);
|
||||
} else {
|
||||
// if the entry is a directory, make the directory
|
||||
File dir = new File(filePath);
|
||||
dir.mkdir();
|
||||
}
|
||||
zipIn.closeEntry();
|
||||
entry = zipIn.getNextEntry();
|
||||
}
|
||||
zipIn.close();
|
||||
}
|
||||
|
||||
protected void extractFile(ZipInputStream zipIn, String filePath) throws IOException {
|
||||
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));
|
||||
byte[] bytesIn = new byte[BUFFER_SIZE];
|
||||
int read;
|
||||
while ((read = zipIn.read(bytesIn)) != -1) {
|
||||
bos.write(bytesIn, 0, read);
|
||||
}
|
||||
bos.close();
|
||||
}
|
||||
|
||||
protected String getGlobal(ImplementationGuide ig, String rt) {
|
||||
for (ImplementationGuide.ImplementationGuideGlobalComponent igg : ig.getGlobal()) {
|
||||
if (rt.equals(igg.getType()))
|
||||
return igg.getProfile();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package org.hl7.fhir.validation;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r5.context.SimpleWorkerContext;
|
||||
import org.hl7.fhir.r5.elementmodel.Manager;
|
||||
import org.hl7.fhir.r5.model.Base;
|
||||
import org.hl7.fhir.r5.model.Coding;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
import org.hl7.fhir.r5.terminologies.ConceptMapEngine;
|
||||
import org.hl7.fhir.r5.utils.structuremap.ITransformerServices;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.List;
|
||||
|
||||
public class TransformSupportServices implements ITransformerServices {
|
||||
|
||||
private final PrintWriter mapLog;
|
||||
private final SimpleWorkerContext context;
|
||||
private List<Base> outputs;
|
||||
|
||||
public TransformSupportServices(List<Base> outputs,
|
||||
PrintWriter mapLog,
|
||||
SimpleWorkerContext context) {
|
||||
this.outputs = outputs;
|
||||
this.mapLog = mapLog;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String message) {
|
||||
if (mapLog != null)
|
||||
mapLog.println(message);
|
||||
System.out.println(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Base createType(Object appInfo, String name) throws FHIRException {
|
||||
StructureDefinition sd = context.fetchResource(StructureDefinition.class, name);
|
||||
return Manager.build(context, sd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Base createResource(Object appInfo, Base res, boolean atRootofTransform) {
|
||||
if (atRootofTransform)
|
||||
outputs.add(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Coding translate(Object appInfo, Coding source, String conceptMapUrl) throws FHIRException {
|
||||
ConceptMapEngine cme = new ConceptMapEngine(context);
|
||||
return cme.translate(source, conceptMapUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Base resolveReference(Object appContext, String url) throws FHIRException {
|
||||
throw new FHIRException("resolveReference is not supported yet");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Base> performSearch(Object appContext, String url) throws FHIRException {
|
||||
throw new FHIRException("performSearch is not supported yet");
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -70,9 +70,6 @@ import org.hl7.fhir.validation.cli.utils.*;
|
||||
import java.io.File;
|
||||
import java.net.Authenticator;
|
||||
import java.net.PasswordAuthentication;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* A executable class that will validate one or more FHIR resources against
|
||||
@ -232,7 +229,8 @@ public class ValidatorCli {
|
||||
}
|
||||
System.out.println("Validating");
|
||||
if (cliContext.getMode() == EngineMode.SCAN) {
|
||||
ValidationService.validateScan(cliContext, validator);
|
||||
Scanner validationScanner = new Scanner(validator.getContext(), validator.getValidator(), validator.getIgLoader(), validator.getFhirPathEngine());
|
||||
validationScanner.validateScan(cliContext.getOutput(), cliContext.getSources());
|
||||
} else {
|
||||
ValidationService.validateSources(cliContext, validator);
|
||||
}
|
||||
|
@ -0,0 +1,149 @@
|
||||
package org.hl7.fhir.validation;
|
||||
|
||||
import org.hl7.fhir.convertors.loaders.*;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r5.context.IWorkerContext;
|
||||
import org.hl7.fhir.r5.context.SimpleWorkerContext;
|
||||
import org.hl7.fhir.r5.model.OperationOutcome;
|
||||
import org.hl7.fhir.r5.renderers.RendererFactory;
|
||||
import org.hl7.fhir.r5.renderers.utils.RenderingContext;
|
||||
import org.hl7.fhir.r5.utils.EOperationOutcome;
|
||||
import org.hl7.fhir.r5.utils.FHIRPathEngine;
|
||||
import org.hl7.fhir.r5.utils.OperationOutcomeUtilities;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.i18n.I18nConstants;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
import org.hl7.fhir.validation.cli.utils.AsteriskFilter;
|
||||
import org.hl7.fhir.validation.cli.utils.Common;
|
||||
import org.w3c.dom.Document;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
//TODO find a home for these and clean it up
|
||||
public class ValidatorUtils {
|
||||
|
||||
protected static void grabNatives(Map<String, byte[]> source, Map<String, byte[]> binaries, String prefix) {
|
||||
for (Map.Entry<String, byte[]> e : source.entrySet()) {
|
||||
if (e.getKey().endsWith(".zip"))
|
||||
binaries.put(prefix + "#" + e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
protected static IWorkerContext.IContextResourceLoader loaderForVersion(String version) {
|
||||
if (Utilities.noString(version))
|
||||
return null;
|
||||
if (version.startsWith("1.0"))
|
||||
return new R2ToR5Loader(new String[]{"Conformance", "StructureDefinition", "ValueSet", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"}, new BaseLoaderR5.NullLoaderKnowledgeProvider());
|
||||
if (version.startsWith("1.4"))
|
||||
return new R2016MayToR5Loader(new String[]{"Conformance", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"}, new BaseLoaderR5.NullLoaderKnowledgeProvider()); // special case
|
||||
if (version.startsWith("3.0"))
|
||||
return new R3ToR5Loader(new String[]{"CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"}, new BaseLoaderR5.NullLoaderKnowledgeProvider());
|
||||
if (version.startsWith("4.0"))
|
||||
return new R4ToR5Loader(new String[]{"CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"}, new BaseLoaderR5.NullLoaderKnowledgeProvider());
|
||||
if (version.startsWith("5.0"))
|
||||
return new R5ToR5Loader(new String[]{"CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"}, new BaseLoaderR5.NullLoaderKnowledgeProvider());
|
||||
return null;
|
||||
}
|
||||
|
||||
protected static Document parseXml(byte[] cnt) throws ParserConfigurationException, SAXException, IOException {
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
// xxe protection
|
||||
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
|
||||
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
|
||||
factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
|
||||
factory.setXIncludeAware(false);
|
||||
factory.setExpandEntityReferences(false);
|
||||
factory.setNamespaceAware(true);
|
||||
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||
return builder.parse(new ByteArrayInputStream(cnt));
|
||||
}
|
||||
|
||||
protected static List<ValidationMessage> filterMessages(List<ValidationMessage> messages) {
|
||||
List<ValidationMessage> filteredValidation = new ArrayList<ValidationMessage>();
|
||||
for (ValidationMessage e : messages) {
|
||||
if (!filteredValidation.contains(e))
|
||||
filteredValidation.add(e);
|
||||
}
|
||||
filteredValidation.sort(null);
|
||||
return filteredValidation;
|
||||
}
|
||||
|
||||
protected static OperationOutcome messagesToOutcome(List<ValidationMessage> messages, SimpleWorkerContext context, FHIRPathEngine fpe) throws IOException, FHIRException, EOperationOutcome {
|
||||
OperationOutcome op = new OperationOutcome();
|
||||
for (ValidationMessage vm : filterMessages(messages)) {
|
||||
try {
|
||||
fpe.parse(vm.getLocation());
|
||||
} catch (Exception e) {
|
||||
System.out.println("Internal error in location for message: '" + e.getMessage() + "', loc = '" + vm.getLocation() + "', err = '" + vm.getMessage() + "'");
|
||||
}
|
||||
op.getIssue().add(OperationOutcomeUtilities.convertToIssue(vm, op));
|
||||
}
|
||||
if (!op.hasIssue()) {
|
||||
op.addIssue().setSeverity(OperationOutcome.IssueSeverity.INFORMATION).setCode(OperationOutcome.IssueType.INFORMATIONAL).getDetails().setText(context.formatMessage(I18nConstants.ALL_OK));
|
||||
}
|
||||
RenderingContext rc = new RenderingContext(context, null, null, "http://hl7.org/fhir", "", null, RenderingContext.ResourceRendererMode.RESOURCE);
|
||||
RendererFactory.factory(op, rc).render(op);
|
||||
return op;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses passed in resource path, adding any found references to the passed in list.
|
||||
*
|
||||
* @return {@link Boolean#TRUE} if more than one reference is found.
|
||||
*/
|
||||
static boolean extractReferences(String name, List<String> refs, SimpleWorkerContext context) throws IOException {
|
||||
if (Common.isNetworkPath(name)) {
|
||||
refs.add(name);
|
||||
} else if (Common.isWildcardPath(name)) {
|
||||
AsteriskFilter filter = new AsteriskFilter(name);
|
||||
File[] files = new File(filter.getDir()).listFiles(filter);
|
||||
for (File file : files) {
|
||||
refs.add(file.getPath());
|
||||
}
|
||||
} else {
|
||||
File file = new File(name);
|
||||
if (!file.exists()) {
|
||||
if (System.console() != null) {
|
||||
System.console().printf(context.formatMessage(I18nConstants.BAD_FILE_PATH_ERROR, name));
|
||||
} else {
|
||||
System.out.println(context.formatMessage(I18nConstants.BAD_FILE_PATH_ERROR, name));
|
||||
}
|
||||
throw new IOException("File " + name + " does not exist");
|
||||
}
|
||||
|
||||
if (file.isFile()) {
|
||||
refs.add(name);
|
||||
} else {
|
||||
for (int i = 0; i < file.listFiles().length; i++) {
|
||||
File[] fileList = file.listFiles();
|
||||
if (fileList[i].isFile())
|
||||
refs.add(fileList[i].getPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
return refs.size() > 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates through the list of passed in sources, extracting all references and populated them in the passed in list.
|
||||
*
|
||||
* @return {@link Boolean#TRUE} if more than one reference is found.
|
||||
*/
|
||||
public static boolean parseSources(List<String> sources, List<String> refs, SimpleWorkerContext context) throws IOException {
|
||||
boolean multipleRefsFound = sources.size() > 1;
|
||||
for (String source : sources) {
|
||||
multipleRefsFound |= extractReferences(source, refs, context);
|
||||
}
|
||||
return multipleRefsFound;
|
||||
}
|
||||
}
|
@ -0,0 +1,173 @@
|
||||
package org.hl7.fhir.validation;
|
||||
|
||||
import org.hl7.fhir.convertors.*;
|
||||
import org.hl7.fhir.dstu2016may.model.Resource;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r5.elementmodel.Manager;
|
||||
import org.hl7.fhir.utilities.VersionUtilities;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class VersionConvertor {
|
||||
|
||||
public static byte[] convertVersionNativeR2(String targetVer, Content cnt, Manager.FhirFormat format) throws IOException, Exception {
|
||||
org.hl7.fhir.dstu2.model.Resource r2;
|
||||
switch (cnt.cntType) {
|
||||
case JSON:
|
||||
r2 = new org.hl7.fhir.dstu2.formats.JsonParser().parse(cnt.focus);
|
||||
break;
|
||||
case XML:
|
||||
r2 = new org.hl7.fhir.dstu2.formats.XmlParser().parse(cnt.focus);
|
||||
break;
|
||||
default:
|
||||
throw new FHIRException("Unsupported input format: " + cnt.cntType.toString());
|
||||
}
|
||||
if (VersionUtilities.isR2Ver(targetVer)) {
|
||||
return getBytesDstu2(cnt, format, r2);
|
||||
} else if (VersionUtilities.isR2BVer(targetVer)) {
|
||||
org.hl7.fhir.dstu3.model.Resource r3 = VersionConvertor_10_30.convertResource(r2);
|
||||
org.hl7.fhir.dstu2016may.model.Resource r2b = VersionConvertor_14_30.convertResource(r3);
|
||||
return getBytesDstu2016(cnt, format, r2b);
|
||||
} else if (VersionUtilities.isR3Ver(targetVer)) {
|
||||
return getBytesDstu3(cnt, format, VersionConvertor_10_30.convertResource(r2));
|
||||
} else if (VersionUtilities.isR4Ver(targetVer)) {
|
||||
return getBytesR4(cnt, format, VersionConvertor_10_40.convertResource(r2));
|
||||
} else {
|
||||
throw new FHIRException("Target Version not supported yet: " + targetVer);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] convertVersionNativeR2b(String targetVer, Content cnt, Manager.FhirFormat format) throws IOException, Exception {
|
||||
org.hl7.fhir.dstu2016may.model.Resource r2b;
|
||||
switch (cnt.cntType) {
|
||||
case JSON:
|
||||
r2b = new org.hl7.fhir.dstu2016may.formats.JsonParser().parse(cnt.focus);
|
||||
break;
|
||||
case XML:
|
||||
r2b = new org.hl7.fhir.dstu2016may.formats.XmlParser().parse(cnt.focus);
|
||||
break;
|
||||
default:
|
||||
throw new FHIRException("Unsupported input format: " + cnt.cntType.toString());
|
||||
}
|
||||
if (VersionUtilities.isR2Ver(targetVer)) {
|
||||
org.hl7.fhir.dstu3.model.Resource r3 = VersionConvertor_14_30.convertResource(r2b);
|
||||
org.hl7.fhir.dstu2.model.Resource r2 = VersionConvertor_10_30.convertResource(r3);
|
||||
return getBytesDstu2(cnt, format, r2);
|
||||
} else if (VersionUtilities.isR2BVer(targetVer)) {
|
||||
return getBytesDstu2016(cnt, format, r2b);
|
||||
} else if (VersionUtilities.isR3Ver(targetVer)) {
|
||||
return getBytesDstu3(cnt, format, VersionConvertor_14_30.convertResource(r2b));
|
||||
} else if (VersionUtilities.isR4Ver(targetVer)) {
|
||||
return getBytesR4(cnt, format, VersionConvertor_14_40.convertResource(r2b));
|
||||
} else {
|
||||
throw new FHIRException("Target Version not supported yet: " + targetVer);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] convertVersionNativeR3(String targetVer, Content cnt, Manager.FhirFormat format) throws IOException, Exception {
|
||||
org.hl7.fhir.dstu3.model.Resource r3;
|
||||
switch (cnt.cntType) {
|
||||
case JSON:
|
||||
r3 = new org.hl7.fhir.dstu3.formats.JsonParser().parse(cnt.focus);
|
||||
break;
|
||||
case XML:
|
||||
r3 = new org.hl7.fhir.dstu3.formats.XmlParser().parse(cnt.focus);
|
||||
break;
|
||||
default:
|
||||
throw new FHIRException("Unsupported input format: " + cnt.cntType.toString());
|
||||
}
|
||||
if (VersionUtilities.isR2Ver(targetVer)) {
|
||||
return getBytesDstu2(cnt, format, VersionConvertor_10_30.convertResource(r3));
|
||||
} else if (VersionUtilities.isR2BVer(targetVer)) {
|
||||
return getBytesDstu2016(cnt, format, VersionConvertor_14_30.convertResource(r3));
|
||||
} else if (VersionUtilities.isR3Ver(targetVer)) {
|
||||
return getBytesDstu3(cnt, format, r3);
|
||||
} else if (VersionUtilities.isR4Ver(targetVer)) {
|
||||
return getBytesR4(cnt, format, VersionConvertor_30_40.convertResource(r3, false));
|
||||
} else {
|
||||
throw new FHIRException("Target Version not supported yet: " + targetVer);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] convertVersionNativeR4(String targetVer, Content cnt, Manager.FhirFormat format) throws IOException, Exception {
|
||||
org.hl7.fhir.r4.model.Resource r4;
|
||||
switch (cnt.cntType) {
|
||||
case JSON:
|
||||
r4 = new org.hl7.fhir.r4.formats.JsonParser().parse(cnt.focus);
|
||||
break;
|
||||
case XML:
|
||||
r4 = new org.hl7.fhir.r4.formats.XmlParser().parse(cnt.focus);
|
||||
break;
|
||||
default:
|
||||
throw new FHIRException("Unsupported input format: " + cnt.cntType.toString());
|
||||
}
|
||||
if (VersionUtilities.isR2Ver(targetVer)) {
|
||||
return getBytesDstu2(cnt, format, VersionConvertor_10_40.convertResource(r4));
|
||||
} else if (VersionUtilities.isR2BVer(targetVer)) {
|
||||
return getBytesDstu2016(cnt, format, VersionConvertor_14_40.convertResource(r4));
|
||||
} else if (VersionUtilities.isR3Ver(targetVer)) {
|
||||
return getBytesDstu3(cnt, format, VersionConvertor_30_40.convertResource(r4, false));
|
||||
} else if (VersionUtilities.isR4Ver(targetVer)) {
|
||||
return getBytesR4(cnt, format, r4);
|
||||
} else {
|
||||
throw new FHIRException("Target Version not supported yet: " + targetVer);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] getBytesDstu2(Content cnt, Manager.FhirFormat format, org.hl7.fhir.dstu2.model.Resource r2) throws IOException {
|
||||
ByteArrayOutputStream bs = new ByteArrayOutputStream();
|
||||
switch (format) {
|
||||
case JSON:
|
||||
new org.hl7.fhir.dstu2.formats.JsonParser().compose(bs, r2);
|
||||
return bs.toByteArray();
|
||||
case XML:
|
||||
new org.hl7.fhir.dstu2.formats.XmlParser().compose(bs, r2);
|
||||
return bs.toByteArray();
|
||||
default:
|
||||
throw new FHIRException("Unsupported output format: " + cnt.cntType.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] getBytesDstu2016(Content cnt, Manager.FhirFormat format, Resource r2b) throws IOException {
|
||||
ByteArrayOutputStream bs = new ByteArrayOutputStream();
|
||||
switch (format) {
|
||||
case JSON:
|
||||
new org.hl7.fhir.dstu2016may.formats.JsonParser().compose(bs, r2b);
|
||||
return bs.toByteArray();
|
||||
case XML:
|
||||
new org.hl7.fhir.dstu2016may.formats.XmlParser().compose(bs, r2b);
|
||||
return bs.toByteArray();
|
||||
default:
|
||||
throw new FHIRException("Unsupported output format: " + cnt.cntType.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] getBytesDstu3(Content cnt, Manager.FhirFormat format, org.hl7.fhir.dstu3.model.Resource r3) throws IOException {
|
||||
ByteArrayOutputStream bs = new ByteArrayOutputStream();
|
||||
switch (format) {
|
||||
case JSON:
|
||||
new org.hl7.fhir.dstu3.formats.JsonParser().compose(bs, r3);
|
||||
return bs.toByteArray();
|
||||
case XML:
|
||||
new org.hl7.fhir.dstu3.formats.XmlParser().compose(bs, r3);
|
||||
return bs.toByteArray();
|
||||
default:
|
||||
throw new FHIRException("Unsupported output format: " + cnt.cntType.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] getBytesR4(Content cnt, Manager.FhirFormat format, org.hl7.fhir.r4.model.Resource r4) throws IOException {
|
||||
ByteArrayOutputStream bs = new ByteArrayOutputStream();
|
||||
switch (format) {
|
||||
case JSON:
|
||||
new org.hl7.fhir.r4.formats.JsonParser().compose(bs, r4);
|
||||
return bs.toByteArray();
|
||||
case XML:
|
||||
new org.hl7.fhir.r4.formats.XmlParser().compose(bs, r4);
|
||||
return bs.toByteArray();
|
||||
default:
|
||||
throw new FHIRException("Unsupported output format: " + cnt.cntType.toString());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package org.hl7.fhir.validation.cli.services;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface IPackageInstaller {
|
||||
boolean packageExists(String id, String ver) throws IOException, FHIRException;
|
||||
void loadPackage(String id, String ver) throws IOException, FHIRException;
|
||||
}
|
@ -1,16 +1,8 @@
|
||||
package org.hl7.fhir.validation.cli.services;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import org.hl7.fhir.convertors.txClient.TerminologyClientFactory;
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||
import org.hl7.fhir.r5.context.IWorkerContext;
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
import org.hl7.fhir.r5.model.CanonicalResource;
|
||||
@ -22,26 +14,23 @@ import org.hl7.fhir.utilities.VersionUtilities;
|
||||
import org.hl7.fhir.utilities.VersionUtilities.VersionURLInfo;
|
||||
import org.hl7.fhir.utilities.json.JSONUtil;
|
||||
import org.hl7.fhir.utilities.json.JsonTrackingParser;
|
||||
import org.hl7.fhir.utilities.npm.BasePackageCacheManager;
|
||||
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
|
||||
import org.hl7.fhir.utilities.npm.NpmPackage;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import ca.uhn.fhir.util.JsonUtil;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class StandAloneValidatorFetcher implements IValidatorResourceFetcher {
|
||||
|
||||
public interface IPackageInstaller {
|
||||
boolean packageExists(String id, String ver) throws IOException, FHIRException;
|
||||
void loadPackage(String id, String ver) throws IOException, FHIRException;
|
||||
}
|
||||
|
||||
List<String> mappingsUris = new ArrayList<>();
|
||||
private FilesystemPackageCacheManager pcm;
|
||||
private IWorkerContext context;
|
||||
private IPackageInstaller installer;
|
||||
|
||||
|
||||
public StandAloneValidatorFetcher(FilesystemPackageCacheManager pcm, IWorkerContext context, IPackageInstaller installer) {
|
||||
super();
|
||||
this.pcm = pcm;
|
||||
@ -50,8 +39,8 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Element fetch(Object appContext, String url) throws FHIRFormatError, DefinitionException, FHIRException, IOException {
|
||||
throw new FHIRException("The URL '"+url+"' is not known to the FHIR validator, and has not been provided as part of the setup / parameters");
|
||||
public Element fetch(Object appContext, String url) throws FHIRException {
|
||||
throw new FHIRException("The URL '" + url + "' is not known to the FHIR validator, and has not been provided as part of the setup / parameters");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -64,15 +53,15 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher {
|
||||
if (!Utilities.isAbsoluteUrl(url)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (url.contains("|")) {
|
||||
url = url.substring(0, url.lastIndexOf("|"));
|
||||
}
|
||||
|
||||
|
||||
if (type.equals("uri") && isMappingUri(url)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// if we've got to here, it's a reference to a FHIR URL. We're going to try to resolve it on the fly
|
||||
String pid = null;
|
||||
String ver = null;
|
||||
@ -80,19 +69,19 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher {
|
||||
if (base == null) {
|
||||
return !url.startsWith("http://hl7.org/fhir") && !type.equals("canonical");
|
||||
}
|
||||
|
||||
|
||||
if (base.equals("http://terminology.hl7.org")) {
|
||||
pid = "hl7.terminology";
|
||||
pid = "hl7.terminology";
|
||||
} else if (url.startsWith("http://hl7.org/fhir")) {
|
||||
pid = pcm.getPackageId(base);
|
||||
} else {
|
||||
} else {
|
||||
pid = pcm.findCanonicalInLocalCache(base);
|
||||
}
|
||||
ver = url.contains("|") ? url.substring(url.indexOf("|")+1) : null;
|
||||
ver = url.contains("|") ? url.substring(url.indexOf("|") + 1) : null;
|
||||
if (pid == null && Utilities.startsWithInList(url, "http://hl7.org/fhir", "http://terminology.hl7.org")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (url.startsWith("http://hl7.org/fhir")) {
|
||||
// first possibility: it's a reference to a version specific URL http://hl7.org/fhir/X.X/...
|
||||
VersionURLInfo vu = VersionUtilities.parseVersionUrl(url);
|
||||
@ -110,9 +99,8 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher {
|
||||
return pi.hasCanonical(url);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// we don't bother with urls outside fhir space in the standalone validator - we assume they are valid
|
||||
// we don't bother with urls outside fhir space in the standalone validator - we assume they are valid
|
||||
return !url.startsWith("http://hl7.org/fhir") && !type.equals("canonical");
|
||||
}
|
||||
|
||||
@ -122,7 +110,7 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher {
|
||||
try {
|
||||
json = JsonTrackingParser.fetchJson("http://hl7.org/fhir/mappingspaces.json");
|
||||
for (JsonObject ms : JSONUtil.objects(json, "spaces")) {
|
||||
mappingsUris.add(JSONUtil.str(ms, "url"));
|
||||
mappingsUris.add(JSONUtil.str(ms, "url"));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// frozen R4 list
|
||||
@ -177,7 +165,7 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher {
|
||||
|
||||
private String findBaseUrl(String url) {
|
||||
String[] p = url.split("\\/");
|
||||
for (int i = 1; i< p.length; i++) {
|
||||
for (int i = 1; i < p.length; i++) {
|
||||
if (Utilities.existsInList(p[i], context.getResourceNames())) {
|
||||
StringBuilder b = new StringBuilder(p[0]);
|
||||
for (int j = 1; j < i; j++) {
|
||||
@ -192,12 +180,14 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher {
|
||||
|
||||
@Override
|
||||
public byte[] fetchRaw(String url) throws MalformedURLException, IOException {
|
||||
throw new FHIRException("The URL '"+url+"' is not known to the FHIR validator, and has not been provided as part of the setup / parameters");
|
||||
throw new FHIRException("The URL '" + url + "' is not known to the FHIR validator, and has not been provided as part of the setup / parameters");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLocale(Locale locale) {
|
||||
public IValidatorResourceFetcher setLocale(Locale locale) {
|
||||
// nothing
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -207,20 +197,19 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher {
|
||||
if (root != null) {
|
||||
TerminologyClient c;
|
||||
c = TerminologyClientFactory.makeClient(root, context.getVersion());
|
||||
return c.read(p[p.length-2], p[p.length-1]);
|
||||
return c.read(p[p.length - 2], p[p.length - 1]);
|
||||
} else {
|
||||
throw new FHIRException("The URL '"+url+"' is not known to the FHIR validator, and has not been provided as part of the setup / parameters");
|
||||
throw new FHIRException("The URL '" + url + "' is not known to the FHIR validator, and has not been provided as part of the setup / parameters");
|
||||
}
|
||||
}
|
||||
|
||||
private String getRoot(String[] p, String url) {
|
||||
if (p.length > 3 && Utilities.isValidId(p[p.length-1]) && context.getResourceNames().contains(p[p.length-2])) {
|
||||
if (p.length > 3 && Utilities.isValidId(p[p.length - 1]) && context.getResourceNames().contains(p[p.length - 2])) {
|
||||
url = url.substring(0, url.lastIndexOf("/"));
|
||||
return url.substring(0, url.lastIndexOf("/"));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,11 +1,8 @@
|
||||
package org.hl7.fhir.validation.cli.services;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hl7.fhir.r5.context.TerminologyCache;
|
||||
import org.hl7.fhir.r5.elementmodel.Manager;
|
||||
@ -15,7 +12,6 @@ import org.hl7.fhir.r5.formats.XmlParser;
|
||||
import org.hl7.fhir.r5.model.Bundle;
|
||||
import org.hl7.fhir.r5.model.DomainResource;
|
||||
import org.hl7.fhir.r5.model.FhirPublication;
|
||||
import org.hl7.fhir.r5.model.ImplementationGuide;
|
||||
import org.hl7.fhir.r5.model.OperationOutcome;
|
||||
import org.hl7.fhir.r5.model.Resource;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
@ -26,6 +22,7 @@ import org.hl7.fhir.utilities.TimeTracker;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.VersionUtilities;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
import org.hl7.fhir.validation.IgLoader;
|
||||
import org.hl7.fhir.validation.ValidationEngine;
|
||||
import org.hl7.fhir.validation.ValidationRecord;
|
||||
import org.hl7.fhir.validation.cli.model.*;
|
||||
@ -62,8 +59,9 @@ public class ValidationService {
|
||||
public static VersionSourceInformation scanForVersions(CliContext cliContext) throws Exception {
|
||||
VersionSourceInformation versions = new VersionSourceInformation();
|
||||
ValidationEngine ve = new ValidationEngine();
|
||||
IgLoader igLoader = new IgLoader(ve.getPcm(), ve.getContext(), ve.getVersion(), ve.isDebug());
|
||||
for (String src : cliContext.getIgs()) {
|
||||
ve.scanForIgVersion(src, cliContext.isRecursive(), versions);
|
||||
igLoader.scanForIgVersion(src, cliContext.isRecursive(), versions);
|
||||
}
|
||||
ve.scanForVersions(cliContext.getSources(), versions);
|
||||
return versions;
|
||||
@ -107,22 +105,6 @@ public class ValidationService {
|
||||
System.exit(ec > 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
public static void validateScan(CliContext cliContext, ValidationEngine validator) throws Exception {
|
||||
if (Utilities.noString(cliContext.getOutput()))
|
||||
throw new Exception("Output parameter required when scanning");
|
||||
if (!(new File(cliContext.getOutput()).isDirectory()))
|
||||
throw new Exception("Output '" + cliContext.getOutput() + "' must be a directory when scanning");
|
||||
System.out.println(" .. scan " + cliContext.getSources() + " against loaded IGs");
|
||||
Set<String> urls = new HashSet<>();
|
||||
for (ImplementationGuide ig : validator.getContext().allImplementationGuides()) {
|
||||
if (ig.getUrl().contains("/ImplementationGuide") && !ig.getUrl().equals("http://hl7.org/fhir/ImplementationGuide/fhir"))
|
||||
urls.add(ig.getUrl());
|
||||
}
|
||||
List<ScanOutputItem> res = validator.validateScan(cliContext.getSources(), urls);
|
||||
validator.genScanOutput(cliContext.getOutput(), res);
|
||||
System.out.println("Done. output in " + Utilities.path(cliContext.getOutput(), "scan.html"));
|
||||
}
|
||||
|
||||
public static void convertSources(CliContext cliContext, ValidationEngine validator) throws Exception {
|
||||
System.out.println(" ...convert");
|
||||
validator.convert(cliContext.getSources().get(0), cliContext.getOutput());
|
||||
@ -212,18 +194,19 @@ public class ValidationService {
|
||||
System.out.print(" Load FHIR v" + cliContext.getSv() + " from " + definitions);
|
||||
FhirPublication ver = FhirPublication.fromCode(cliContext.getSv());
|
||||
ValidationEngine validator = new ValidationEngine(definitions, ver, cliContext.getSv(), tt);
|
||||
IgLoader igLoader = new IgLoader(validator.getPcm(), validator.getContext(), validator.getVersion(), validator.isDebug());
|
||||
System.out.println(" - "+validator.getContext().countAllCaches()+" resources ("+tt.milestone()+")");
|
||||
validator.loadIg("hl7.terminology", false);
|
||||
igLoader.loadIg(validator.getIgs(), validator.getBinaries(), "hl7.terminology", false);
|
||||
System.out.print(" Terminology server " + cliContext.getTxServer());
|
||||
String txver = validator.setTerminologyServer(cliContext.getTxServer(), cliContext.getTxLog(), ver);
|
||||
System.out.println(" - Version "+txver+" ("+tt.milestone()+")");
|
||||
validator.setDebug(cliContext.isDoDebug());
|
||||
for (String src : cliContext.getIgs()) {
|
||||
validator.loadIg(src, cliContext.isRecursive());
|
||||
igLoader.loadIg(validator.getIgs(), validator.getBinaries(), src, cliContext.isRecursive());
|
||||
}
|
||||
System.out.print(" Get set... ");
|
||||
validator.setQuestionnaireMode(cliContext.getQuestionnaireMode());
|
||||
validator.setNative(cliContext.isDoNative());
|
||||
validator.setDoNative(cliContext.isDoNative());
|
||||
validator.setHintAboutNonMustSupport(cliContext.isHintAboutNonMustSupport());
|
||||
validator.setAnyExtensionsAllowed(cliContext.isAnyExtensionsAllowed());
|
||||
validator.setLanguage(cliContext.getLang());
|
||||
|
@ -5,6 +5,7 @@ import java.text.NumberFormat;
|
||||
import org.hl7.fhir.r5.test.utils.TestingUtilities;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.VersionUtilities;
|
||||
import org.hl7.fhir.validation.IgLoader;
|
||||
import org.hl7.fhir.validation.ValidationEngine;
|
||||
import org.junit.Test;
|
||||
|
||||
@ -21,9 +22,10 @@ public class LoadIgTests {
|
||||
final String definitions = VersionUtilities.packageForVersion(fhirSpecVersion) + "#" + VersionUtilities.getCurrentVersion(fhirSpecVersion);
|
||||
|
||||
ValidationEngine hl7Validator = new ValidationEngine(definitions);
|
||||
hl7Validator.setNative(false);
|
||||
hl7Validator.setDoNative(false);
|
||||
hl7Validator.setAnyExtensionsAllowed(true);
|
||||
hl7Validator.prepare();
|
||||
IgLoader igLoader = new IgLoader(hl7Validator.getPcm(), hl7Validator.getContext(), hl7Validator.getVersion(), true);
|
||||
|
||||
for (int i = 0; i < DO_TIMES; i++) {
|
||||
System.gc();
|
||||
@ -32,7 +34,7 @@ public class LoadIgTests {
|
||||
System.out.println("max memory " + getTotalMemoryAsMbs() + " MB");
|
||||
|
||||
// The method under test:
|
||||
hl7Validator.loadIg(id + (version != null ? "#" + version : ""), true);
|
||||
igLoader.loadIg(hl7Validator.getIgs(), hl7Validator.getBinaries(),id + (version != null ? "#" + version : ""), true);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@ -51,23 +53,24 @@ public class LoadIgTests {
|
||||
final String definitions = VersionUtilities.packageForVersion(fhirSpecVersion) + "#" + VersionUtilities.getCurrentVersion(fhirSpecVersion);
|
||||
|
||||
ValidationEngine hl7Validator = new ValidationEngine(definitions);
|
||||
hl7Validator.setNative(false);
|
||||
hl7Validator.setDoNative(false);
|
||||
hl7Validator.setAnyExtensionsAllowed(true);
|
||||
hl7Validator.prepare();
|
||||
IgLoader igLoader = new IgLoader(hl7Validator.getPcm(), hl7Validator.getContext(), hl7Validator.getVersion(), true);
|
||||
|
||||
byte[] b = TextFile.streamToBytes(TestingUtilities.loadTestResourceStream("r5", "snapshot-generation", "t34-expected.xml")); // yes the choice of R5 is deliberate here - it's the same content as R4.
|
||||
for (int i = 0; i < DO_TIMES; i++) {
|
||||
System.gc();
|
||||
|
||||
for (int j = 0; j < 100; j++) {
|
||||
hl7Validator.loadResourceByVersion("4.0.1", b, "resource.xml");
|
||||
igLoader.loadResourceByVersion("4.0.1", b, "resource.xml");
|
||||
}
|
||||
System.out.print("loading: allocated memory " + getUsedMemoryAsMbs() + " MB, ");
|
||||
System.out.print("free memory " + getFreeMemoryAsMbs() + " MB, ");
|
||||
System.out.println("max memory " + getTotalMemoryAsMbs() + " MB");
|
||||
|
||||
// The method under test:
|
||||
hl7Validator.loadIg(id + (version != null ? "#" + version : ""), true);
|
||||
igLoader.loadIg(hl7Validator.getIgs(), hl7Validator.getBinaries(), id + (version != null ? "#" + version : ""), true);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
@ -9,6 +9,7 @@ import org.hl7.fhir.r5.model.OperationOutcome;
|
||||
import org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity;
|
||||
import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent;
|
||||
import org.hl7.fhir.r5.test.utils.TestingUtilities;
|
||||
import org.hl7.fhir.validation.IgLoader;
|
||||
import org.hl7.fhir.validation.ValidationEngine;
|
||||
import org.hl7.fhir.validation.tests.utilities.TestUtilities;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
@ -157,9 +158,10 @@ public class ValidationEngineTests {
|
||||
if (!TestUtilities.silent)
|
||||
System.out.println("Test301USCore: Validate patient300.xml against US-Core");
|
||||
ValidationEngine ve = new ValidationEngine("hl7.fhir.r3.core#3.0.2", DEF_TX, null, FhirPublication.STU3, "3.0.2");
|
||||
IgLoader igLoader = new IgLoader(ve.getPcm(), ve.getContext(), ve.getVersion(), true);
|
||||
if (!TestUtilities.silent)
|
||||
System.out.println(" .. load USCore");
|
||||
ve.loadIg("hl7.fhir.us.core#1.0.1", false);
|
||||
igLoader.loadIg(ve.getIgs(), ve.getBinaries(), "hl7.fhir.us.core#1.0.1", false);
|
||||
List<String> profiles = new ArrayList<>();
|
||||
profiles.add("http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient");
|
||||
OperationOutcome op = ve.validate(FhirFormat.XML, TestingUtilities.loadTestResourceStream("validator", "patient301.xml"), profiles);
|
||||
|
@ -12,7 +12,6 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.NotImplementedException;
|
||||
@ -56,6 +55,7 @@ import org.hl7.fhir.utilities.json.JSONUtil;
|
||||
import org.hl7.fhir.utilities.npm.NpmPackage;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
import org.hl7.fhir.validation.IgLoader;
|
||||
import org.hl7.fhir.validation.ValidationEngine;
|
||||
import org.hl7.fhir.validation.cli.services.StandAloneValidatorFetcher;
|
||||
import org.hl7.fhir.validation.instance.InstanceValidator;
|
||||
@ -108,6 +108,7 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
|
||||
// private static final String DEF_TX = "http://local.fhir.org:960";
|
||||
private static Map<String, ValidationEngine> ve = new HashMap<>();
|
||||
private static ValidationEngine vCurr;
|
||||
private static IgLoader igLoader;
|
||||
|
||||
public ValidationTests(String name, JsonObject content) {
|
||||
this.name = name;
|
||||
@ -148,6 +149,7 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
|
||||
throw new Exception("unknown version " + version);
|
||||
}
|
||||
vCurr = ve.get(version);
|
||||
igLoader = new IgLoader(vCurr.getPcm(), vCurr.getContext(), vCurr.getVersion(), true);
|
||||
if (TestingUtilities.fcontexts == null) {
|
||||
TestingUtilities.fcontexts = new HashMap<>();
|
||||
}
|
||||
@ -181,9 +183,9 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
|
||||
String n = e.getAsString();
|
||||
InputStream cnt = n.endsWith(".tgz") ? TestingUtilities.loadTestResourceStream("validator", n) : null;
|
||||
if (cnt != null) {
|
||||
vCurr.loadPackage(NpmPackage.fromPackage(cnt));
|
||||
igLoader.loadPackage(NpmPackage.fromPackage(cnt));
|
||||
} else {
|
||||
vCurr.loadIg(n, true);
|
||||
igLoader.loadIg(vCurr.getIgs(), vCurr.getBinaries(), n, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -289,7 +291,7 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
|
||||
}
|
||||
if (logical.has("packages")) {
|
||||
for (JsonElement e : logical.getAsJsonArray("packages")) {
|
||||
vCurr.loadIg(e.getAsString(), true);
|
||||
igLoader.loadIg(vCurr.getIgs(), vCurr.getBinaries(), e.getAsString(), true);
|
||||
}
|
||||
}
|
||||
List<ValidationMessage> errorsLogical = new ArrayList<ValidationMessage>();
|
||||
@ -495,8 +497,9 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLocale(Locale locale) {
|
||||
public IValidatorResourceFetcher setLocale(Locale locale) {
|
||||
//do nothing
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Loading…
x
Reference in New Issue
Block a user