Validator cleanup (#365)

* cleaning up validator class

* wip

* I left my debug code in
This commit is contained in:
Mark Iantorno 2020-10-16 10:44:01 -04:00 committed by GitHub
parent 9bbb78e23d
commit 36fa3a97af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 667 additions and 799 deletions

View File

@ -67,7 +67,6 @@ public class TimeTracker {
c.count++; c.count++;
c.length = c.length + System.nanoTime() - session.start; c.length = c.length + System.nanoTime() - session.start;
} }
public String report() { public String report() {
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();

View File

@ -6,9 +6,7 @@ public class TimeTracker {
private long sdTime = 0; private long sdTime = 0;
private long loadTime = 0; private long loadTime = 0;
private long fpeTime = 0; private long fpeTime = 0;
public long getOverall() { public long getOverall() {
return overall; return overall;
} }
@ -51,7 +49,5 @@ public class TimeTracker {
sdTime = 0; sdTime = 0;
loadTime = 0; loadTime = 0;
fpeTime = 0; fpeTime = 0;
} }
} }

View File

@ -1,33 +1,33 @@
package org.hl7.fhir.validation; package org.hl7.fhir.validation;
/* /*
Copyright (c) 2011+, HL7, Inc. Copyright (c) 2011+, HL7, Inc.
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met: are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this * Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer. list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, * Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution. and/or other materials provided with the distribution.
* Neither the name of HL7 nor the names of its contributors may be used to * 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 endorse or promote products derived from this software without specific
prior written permission. prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 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 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 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, IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 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, PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. POSSIBILITY OF SUCH DAMAGE.
*/ */
/* /*
Copyright (c) 2011+, HL7, Inc Copyright (c) 2011+, HL7, Inc
@ -58,22 +58,16 @@ POSSIBILITY OF SUCH DAMAGE.
*/ */
import java.io.File;
import java.net.URI;
import org.hl7.fhir.r5.model.ImplementationGuide; import org.hl7.fhir.r5.model.ImplementationGuide;
import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.utilities.TimeTracker; import org.hl7.fhir.utilities.TimeTracker;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.validation.ValidationEngine.VersionSourceInformation;
import org.hl7.fhir.validation.cli.ValidatorGui;
import org.hl7.fhir.validation.cli.model.CliContext; import org.hl7.fhir.validation.cli.model.CliContext;
import org.hl7.fhir.validation.cli.services.ComparisonService; import org.hl7.fhir.validation.cli.services.ComparisonService;
import org.hl7.fhir.validation.cli.services.ValidationService; import org.hl7.fhir.validation.cli.services.ValidationService;
import org.hl7.fhir.validation.cli.utils.Common; import org.hl7.fhir.validation.cli.utils.*;
import org.hl7.fhir.validation.cli.utils.Display;
import org.hl7.fhir.validation.cli.utils.Params; import java.io.File;
/** /**
* A executable class that will validate one or more FHIR resources against * A executable class that will validate one or more FHIR resources against
@ -84,125 +78,108 @@ import org.hl7.fhir.validation.cli.utils.Params;
* if you want to host validation inside a process, skip this class, and look at * if you want to host validation inside a process, skip this class, and look at
* ValidationEngine * ValidationEngine
* <p> * <p>
* todo: find a gome for this: * todo: find a home for this:
* *
* @author Grahame * @author Grahame
*/ */
public class Validator { public class Validator {
public enum EngineMode { public static final String HTTP_PROXY_HOST = "http.proxyHost";
VALIDATION, TRANSFORM, NARRATIVE, SNAPSHOT, SCAN, CONVERT, FHIRPATH, VERSION public static final String HTTP_PROXY_PORT = "http.proxyPort";
}
public enum QuestionnaireMode { NONE, CHECK, REQUIRED }
private static CliContext cliContext;
private static String getNamedParam(String[] args, String param) {
boolean found = false;
for (String a : args) {
if (found)
return a;
if (a.equals(param)) {
found = true;
}
}
return null;
}
private static String toMB(long maxMemory) {
return Long.toString(maxMemory / (1024 * 1024));
}
private static CliContext getCliContext() {
if (cliContext == null) {
cliContext = new CliContext();
}
return cliContext;
}
private static void goToWebPage(String url) {
try {
URI uri= new URI(url);
java.awt.Desktop.getDesktop().browse(uri);
System.out.println("Web page opened in browser");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
TimeTracker tt = new TimeTracker(); TimeTracker tt = new TimeTracker();
TimeTracker.Session tts = tt.start("Loading"); TimeTracker.Session tts = tt.start("Loading");
System.out.println("FHIR Validation tool " + VersionUtil.getVersionString()); Display.displayVersion();
System.out.println(" Java: " + System.getProperty("java.version") + " from " + System.getProperty("java.home") + " on " + System.getProperty("os.arch") + " (" + System.getProperty("sun.arch.data.model") + "bit). " + toMB(Runtime.getRuntime().maxMemory()) + "MB available"); Display.displaySystemInfo();
String proxy = getNamedParam(args, Params.PROXY);
if (!Utilities.noString(proxy)) { if (Params.hasParam(args, Params.PROXY)) {
String[] p = proxy.split("\\:"); String[] p = Params.getParam(args, Params.PROXY).split("\\:");
System.setProperty("http.proxyHost", p[0]); System.setProperty(HTTP_PROXY_HOST, p[0]);
System.setProperty("http.proxyPort", p[1]); System.setProperty(HTTP_PROXY_PORT, p[1]);
} }
if (Params.hasParam(args, Params.GUI)) { CliContext cliContext = Params.loadCliContext(args);
cliContext = Params.loadCliContext(args);
String v = Common.getVersion(args); if (Params.hasParam(args, Params.TEST)) {
String definitions = VersionUtilities.packageForVersion(v) + "#" + v;
ValidationEngine validationEngine = Common.getValidationEngine(v, definitions, cliContext.getTxLog(), null);
ValidatorGui.start(cliContext, validationEngine, true);
} else if (Params.hasParam(args, Params.TEST)) {
Common.runValidationEngineTests(); Common.runValidationEngineTests();
} else if (args.length == 0 || Params.hasParam(args, Params.HELP) || Params.hasParam(args, "?") || Params.hasParam(args, "-?") || Params.hasParam(args, "/?")) { } else if (shouldDisplayHelpToUser(args)) {
Display.displayHelpDetails(); Display.displayHelpDetails();
} else if (Params.hasParam(args, Params.COMPARE)) { } else if (Params.hasParam(args, Params.COMPARE)) {
Display.printCliArgumentsAndInfo(args); if (destinationDirectoryValid(Params.getParam(args, Params.DESTINATION))) {
String dest = Params.getParam(args, Params.DESTINATION); doLeftRightComparison(args, cliContext, tt);
if (dest == null)
System.out.println("no -dest parameter provided");
else if (!new File(dest).isDirectory())
System.out.println("Specified destination (-dest parameter) is not valid: \"" + dest + "\")");
else {
// first, prepare the context
cliContext = Params.loadCliContext(args);
if (cliContext.getSv() == null) {
cliContext.setSv(determineVersion(cliContext));
}
String v = VersionUtilities.getCurrentVersion(cliContext.getSv());
String definitions = VersionUtilities.packageForVersion(v) + "#" + v;
ValidationEngine validator = ValidationService.getValidator(cliContext, definitions, tt);
ComparisonService.doLeftRightComparison(args, dest, validator);
} }
} else { } else {
Display.printCliArgumentsAndInfo(args); Display.printCliArgumentsAndInfo(args);
cliContext = Params.loadCliContext(args); doValidation(tt, tts, cliContext);
}
}
if (cliContext.getSv() == null) { private static boolean destinationDirectoryValid(String dest) {
cliContext.setSv(determineVersion(cliContext)); if (dest == null) {
} System.out.println("no -dest parameter provided");
return false;
} else if (!new File(dest).isDirectory()) {
System.out.println("Specified destination (-dest parameter) is not valid: \"" + dest + "\")");
return false;
} else {
System.out.println("Valid destination directory provided: \"" + dest + "\")");
return true;
}
}
System.out.println("Loading"); private static boolean shouldDisplayHelpToUser(String[] args) {
// Comment this out because definitions filename doesn't necessarily contain version (and many not even be 14 characters long). Version gets spit out a couple of lines later after we've loaded the context return (args.length == 0
String definitions = VersionUtilities.packageForVersion(cliContext.getSv()) + "#" + VersionUtilities.getCurrentVersion(cliContext.getSv()); || Params.hasParam(args, Params.HELP)
ValidationEngine validator = ValidationService.getValidator(cliContext, definitions, tt); || Params.hasParam(args, "?")
tts.end(); || Params.hasParam(args, "-?")
if (cliContext.getMode() == EngineMode.VERSION) { || Params.hasParam(args, "/?"));
}
ValidationService.transformVersion(cliContext, validator); private static void doLeftRightComparison(String[] args, CliContext cliContext, TimeTracker tt) throws Exception {
} else if (cliContext.getMode() == EngineMode.TRANSFORM) { Display.printCliArgumentsAndInfo(args);
if (cliContext.getSv() == null) {
cliContext.setSv(determineVersion(cliContext));
}
String v = VersionUtilities.getCurrentVersion(cliContext.getSv());
String definitions = VersionUtilities.packageForVersion(v) + "#" + v;
ValidationEngine validator = ValidationService.getValidator(cliContext, definitions, tt);
ComparisonService.doLeftRightComparison(args, Params.getParam(args, Params.DESTINATION), validator);
}
private static void doValidation(TimeTracker tt, TimeTracker.Session tts, CliContext cliContext) throws Exception {
if (cliContext.getSv() == null) {
cliContext.setSv(determineVersion(cliContext));
}
System.out.println("Loading");
// Comment this out because definitions filename doesn't necessarily contain version (and many not even be 14 characters long).
// Version gets spit out a couple of lines later after we've loaded the context
String definitions = VersionUtilities.packageForVersion(cliContext.getSv()) + "#" + VersionUtilities.getCurrentVersion(cliContext.getSv());
ValidationEngine validator = ValidationService.getValidator(cliContext, definitions, tt);
tts.end();
switch (cliContext.getMode()) {
case TRANSFORM:
ValidationService.transform(cliContext, validator); ValidationService.transform(cliContext, validator);
} else if (cliContext.getMode() == EngineMode.NARRATIVE) { break;
case NARRATIVE:
ValidationService.generateNarrative(cliContext, validator); ValidationService.generateNarrative(cliContext, validator);
} else if (cliContext.getMode() == EngineMode.SNAPSHOT) { break;
case SNAPSHOT:
ValidationService.generateSnapshot(cliContext, validator); ValidationService.generateSnapshot(cliContext, validator);
} else if (cliContext.getMode() == EngineMode.CONVERT) { break;
case CONVERT:
ValidationService.convertSources(cliContext, validator); ValidationService.convertSources(cliContext, validator);
} else if (cliContext.getMode() == EngineMode.FHIRPATH) { break;
case FHIRPATH:
ValidationService.evaluateFhirpath(cliContext, validator); ValidationService.evaluateFhirpath(cliContext, validator);
} else { break;
case VERSION:
ValidationService.transformVersion(cliContext, validator);
break;
case VALIDATION:
case SCAN:
default:
for (String s : cliContext.getProfiles()) { for (String s : cliContext.getProfiles()) {
if (!validator.getContext().hasResource(StructureDefinition.class, s) && !validator.getContext().hasResource(ImplementationGuide.class, s)) { if (!validator.getContext().hasResource(StructureDefinition.class, s) && !validator.getContext().hasResource(ImplementationGuide.class, s)) {
System.out.println(" Fetch Profile from " + s); System.out.println(" Fetch Profile from " + s);
@ -215,10 +192,9 @@ public class Validator {
} else { } else {
ValidationService.validateSources(cliContext, validator); ValidationService.validateSources(cliContext, validator);
} }
} break;
System.out.println("Done. "+tt.report());
} }
System.out.println("Done. " + tt.report());
} }
public static String determineVersion(CliContext cliContext) throws Exception { public static String determineVersion(CliContext cliContext) throws Exception {
@ -228,17 +204,17 @@ public class Validator {
System.out.println("Scanning for versions (no -version parameter):"); System.out.println("Scanning for versions (no -version parameter):");
VersionSourceInformation versions = ValidationService.scanForVersions(cliContext); VersionSourceInformation versions = ValidationService.scanForVersions(cliContext);
for (String s : versions.getReport()) { for (String s : versions.getReport()) {
System.out.println(" "+s); System.out.println(" " + s);
} }
if (versions.isEmpty()) { if (versions.isEmpty()) {
System.out.println("-> Using Default version '"+VersionUtilities.CURRENT_VERSION+"'"); System.out.println("-> Using Default version '" + VersionUtilities.CURRENT_VERSION + "'");
return "current"; return "current";
} }
if (versions.size() == 1) { if (versions.size() == 1) {
System.out.println("-> use version "+versions.version()); System.out.println("-> use version " + versions.version());
return versions.version(); return versions.version();
} }
throw new Exception("-> Multiple versions found. Specify a particular version using the -version parameter"); throw new Exception("-> Multiple versions found. Specify a particular version using the -version parameter");
} }
} }

View File

@ -8,7 +8,8 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import org.hl7.fhir.r5.utils.IResourceValidator.BundleValidationRule; import org.hl7.fhir.r5.utils.IResourceValidator.BundleValidationRule;
import org.hl7.fhir.validation.Validator; import org.hl7.fhir.validation.cli.utils.QuestionnaireMode;
import org.hl7.fhir.validation.cli.utils.EngineMode;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
@ -60,7 +61,7 @@ public class CliContext {
@JsonProperty("igs") @JsonProperty("igs")
private List<String> igs = new ArrayList<String>(); private List<String> igs = new ArrayList<String>();
@JsonProperty("questionnaire") @JsonProperty("questionnaire")
private Validator.QuestionnaireMode questionnaireMode = Validator.QuestionnaireMode.CHECK; private QuestionnaireMode questionnaireMode = QuestionnaireMode.CHECK;
@JsonProperty("profiles") @JsonProperty("profiles")
private List<String> profiles = new ArrayList<String>(); private List<String> profiles = new ArrayList<String>();
@ -68,7 +69,7 @@ public class CliContext {
private List<String> sources = new ArrayList<String>(); private List<String> sources = new ArrayList<String>();
@JsonProperty("mode") @JsonProperty("mode")
private Validator.EngineMode mode = Validator.EngineMode.VALIDATION; private EngineMode mode = EngineMode.VALIDATION;
@JsonProperty("securityChecks") @JsonProperty("securityChecks")
private boolean securityChecks = false; private boolean securityChecks = false;
@ -125,12 +126,12 @@ public class CliContext {
} }
@JsonProperty("questionnaire") @JsonProperty("questionnaire")
public Validator.QuestionnaireMode getQuestionnaireMode() { public QuestionnaireMode getQuestionnaireMode() {
return questionnaireMode; return questionnaireMode;
} }
@JsonProperty("questionnaire") @JsonProperty("questionnaire")
public CliContext setQuestionnaireMode(Validator.QuestionnaireMode questionnaireMode) { public CliContext setQuestionnaireMode(QuestionnaireMode questionnaireMode) {
this.questionnaireMode = questionnaireMode; this.questionnaireMode = questionnaireMode;
return this; return this;
} }
@ -230,12 +231,12 @@ public class CliContext {
} }
@JsonProperty("mode") @JsonProperty("mode")
public Validator.EngineMode getMode() { public EngineMode getMode() {
return mode; return mode;
} }
@JsonProperty("mode") @JsonProperty("mode")
public CliContext setMode(Validator.EngineMode mode) { public CliContext setMode(EngineMode mode) {
this.mode = mode; this.mode = mode;
return this; return this;
} }
@ -494,4 +495,40 @@ public class CliContext {
public int hashCode() { public int hashCode() {
return Objects.hash(doNative, anyExtensionsAllowed, hintAboutNonMustSupport, recursive, doDebug, assumeValidRestReferences, canDoNative, noInternalCaching, noExtensibleBindingMessages, map, output, txServer, sv, txLog, mapLog, lang, fhirpath, snomedCT, targetVer, igs, questionnaireMode, profiles, sources, mode, locale, locations, crumbTrails, showTimes); return Objects.hash(doNative, anyExtensionsAllowed, hintAboutNonMustSupport, recursive, doDebug, assumeValidRestReferences, canDoNative, noInternalCaching, noExtensibleBindingMessages, map, output, txServer, sv, txLog, mapLog, lang, fhirpath, snomedCT, targetVer, igs, questionnaireMode, profiles, sources, mode, locale, locations, crumbTrails, showTimes);
} }
@Override
public String toString() {
return "CliContext{" +
"doNative=" + doNative +
", anyExtensionsAllowed=" + anyExtensionsAllowed +
", hintAboutNonMustSupport=" + hintAboutNonMustSupport +
", recursive=" + recursive +
", doDebug=" + doDebug +
", assumeValidRestReferences=" + assumeValidRestReferences +
", canDoNative=" + canDoNative +
", noInternalCaching=" + noInternalCaching +
", noExtensibleBindingMessages=" + noExtensibleBindingMessages +
", map='" + map + '\'' +
", output='" + output + '\'' +
", txServer='" + txServer + '\'' +
", sv='" + sv + '\'' +
", txLog='" + txLog + '\'' +
", mapLog='" + mapLog + '\'' +
", lang='" + lang + '\'' +
", fhirpath='" + fhirpath + '\'' +
", snomedCT='" + snomedCT + '\'' +
", targetVer='" + targetVer + '\'' +
", igs=" + igs +
", questionnaireMode=" + questionnaireMode +
", profiles=" + profiles +
", sources=" + sources +
", mode=" + mode +
", securityChecks=" + securityChecks +
", crumbTrails=" + crumbTrails +
", showTimes=" + showTimes +
", locale='" + locale + '\'' +
", locations=" + locations +
", bundleValidationRules=" + bundleValidationRules +
'}';
}
} }

View File

@ -0,0 +1,53 @@
package org.hl7.fhir.validation.cli.model;
import org.hl7.fhir.r5.model.ImplementationGuide;
import org.hl7.fhir.r5.model.OperationOutcome;
import org.hl7.fhir.r5.model.StructureDefinition;
public class ScanOutputItem {
private String ref;
private ImplementationGuide ig;
private StructureDefinition profile;
private OperationOutcome outcome;
private String id;
public ScanOutputItem(String ref, ImplementationGuide ig, StructureDefinition profile, OperationOutcome outcome) {
super();
this.ref = ref;
this.ig = ig;
this.profile = profile;
this.outcome = outcome;
}
public String getRef() {
return ref;
}
public ImplementationGuide getIg() {
return ig;
}
public StructureDefinition getProfile() {
return profile;
}
public OperationOutcome getOutcome() {
return outcome;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
if (profile != null)
return "Validate " + ref + " against " + profile.present() + " (" + profile.getUrl() + ")";
if (ig != null)
return "Validate " + ref + " against global profile specified in " + ig.present() + " (" + ig.getUrl() + ")";
return "Validate " + ref + " against FHIR Spec";
}
}

View File

@ -26,12 +26,8 @@ import org.hl7.fhir.utilities.TimeTracker;
import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.validation.ValidationEngine; import org.hl7.fhir.validation.ValidationEngine;
import org.hl7.fhir.validation.ValidationEngine.VersionSourceInformation; import org.hl7.fhir.validation.cli.model.*;
import org.hl7.fhir.validation.cli.model.CliContext; import org.hl7.fhir.validation.cli.utils.VersionSourceInformation;
import org.hl7.fhir.validation.cli.model.FileInfo;
import org.hl7.fhir.validation.cli.model.ValidationOutcome;
import org.hl7.fhir.validation.cli.model.ValidationRequest;
import org.hl7.fhir.validation.cli.model.ValidationResponse;
public class ValidationService { public class ValidationService {
@ -110,7 +106,7 @@ public class ValidationService {
if (ig.getUrl().contains("/ImplementationGuide") && !ig.getUrl().equals("http://hl7.org/fhir/ImplementationGuide/fhir")) if (ig.getUrl().contains("/ImplementationGuide") && !ig.getUrl().equals("http://hl7.org/fhir/ImplementationGuide/fhir"))
urls.add(ig.getUrl()); urls.add(ig.getUrl());
} }
List<ValidationEngine.ScanOutputItem> res = validator.validateScan(cliContext.getSources(), urls); List<ScanOutputItem> res = validator.validateScan(cliContext.getSources(), urls);
validator.genScanOutput(cliContext.getOutput(), res); validator.genScanOutput(cliContext.getOutput(), res);
System.out.println("Done. output in " + Utilities.path(cliContext.getOutput(), "scan.html")); System.out.println("Done. output in " + Utilities.path(cliContext.getOutput(), "scan.html"));
} }

View File

@ -0,0 +1,41 @@
package org.hl7.fhir.validation.cli.utils;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
public class AsteriskFilter implements FilenameFilter {
String dir;
String regex;
public AsteriskFilter(String filter) throws IOException {
if (!filter.matches("(.*(\\\\|\\/))*(.*)\\*(.*)"))
throw new IOException("Filter names must have the following syntax: [directorypath][prefix]?*[suffix]? I.e. The asterisk must be in the filename, not the directory path");
dir = filter.replaceAll("(.*(\\\\|\\/))*(.*)\\*(.*)", "$1");
String expression = filter.replaceAll("(.*(\\\\|\\/))*(.*)", "$3");
regex = "";
for (int i = 0; i < expression.length(); i++) {
if (Character.isAlphabetic(expression.codePointAt(i)) || Character.isDigit(expression.codePointAt(i)))
regex = regex + expression.charAt(i);
else if (expression.charAt(i)=='*')
regex = regex + ".*";
else
regex = regex + "\\" + expression.charAt(i);
}
File f = new File(dir);
if (!f.exists()) {
throw new IOException("Directory " + dir + " does not exist");
}
if (!f.isDirectory()) {
throw new IOException("Directory " + dir + " is not a directory");
}
}
public boolean accept(File dir, String s) {
return s.matches(regex);
}
public String getDir() {
return dir;
}
}

View File

@ -92,4 +92,12 @@ public class Common {
return ve; return ve;
} }
public static boolean isNetworkPath(String path) {
return path.startsWith("https:") || path.startsWith("http:");
}
public static boolean isWildcardPath(String name) {
return name.contains("*");
}
} }

View File

@ -1,11 +1,15 @@
package org.hl7.fhir.validation.cli.utils; package org.hl7.fhir.validation.cli.utils;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.hl7.fhir.r5.model.Constants; import org.hl7.fhir.r5.model.Constants;
import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
import org.hl7.fhir.utilities.npm.ToolsVersion; import org.hl7.fhir.utilities.npm.ToolsVersion;
import org.hl7.fhir.validation.VersionUtil;
/** /**
* Class for displaying output to the cli user. * Class for displaying output to the cli user.
@ -14,6 +18,10 @@ import org.hl7.fhir.utilities.npm.ToolsVersion;
*/ */
public class Display { public class Display {
private static String toMB(long maxMemory) {
return Long.toString(maxMemory / (1024 * 1024));
}
public static void printCliArgumentsAndInfo(String[] args) throws IOException { public static void printCliArgumentsAndInfo(String[] args) throws IOException {
System.out.println(" Paths: Current = " + System.getProperty("user.dir") + ", Package Cache = " + new FilesystemPackageCacheManager(true, ToolsVersion.TOOLS_VERSION).getFolder()); System.out.println(" Paths: Current = " + System.getProperty("user.dir") + ", Package Cache = " + new FilesystemPackageCacheManager(true, ToolsVersion.TOOLS_VERSION).getFolder());
System.out.print(" Params:"); System.out.print(" Params:");
@ -23,128 +31,35 @@ public class Display {
System.out.println(); System.out.println();
} }
/**
* Loads the help details from resources/help.txt, and displays them on the command line to the user.
*/
public static void displayHelpDetails() { public static void displayHelpDetails() {
System.out.println(""); ClassLoader classLoader = Display.class.getClassLoader();
System.out.println("The FHIR validation tool validates a FHIR resource or bundle."); File file = new File(classLoader.getResource("help.txt").getFile());
System.out.println("The validation tool compares a resource against the base definitions and any"); try {
System.out.println("profiles declared in the resource (Resource.meta.profile) or specified on the "); String data = FileUtils.readFileToString(file, "UTF-8");
System.out.println("command line"); System.out.println(data);
System.out.println(""); } catch (IOException e) {
System.out.println("The FHIR validation tool validates a FHIR resource or bundle."); e.printStackTrace();
System.out.println("Schema and schematron checking is performed, then some additional checks are performed. "); }
System.out.println("* XML & Json (FHIR versions 1.0, 1.4, 3.0, 4.0, " + Constants.VERSION_MM + ")");
System.out.println("* Turtle (FHIR versions 3.0, 4.0, " + Constants.VERSION_MM + ")");
System.out.println("");
System.out.println("If requested, instances will also be verified against the appropriate schema");
System.out.println("W3C XML Schema, JSON schema or ShEx, as appropriate");
System.out.println("");
System.out.println("Usage: java -jar [validator].jar (parameters)");
System.out.println("");
System.out.println("The following parameters are supported:");
System.out.println("[source]: a file, url, directory or pattern for resources to validate. At");
System.out.println(" least one source must be declared. If there is more than one source or if");
System.out.println(" the source is other than a single file or url and the output parameter is");
System.out.println(" used, results will be provided as a Bundle.");
System.out.println(" Patterns are limited to a directory followed by a filename with an embedded");
System.out.println(" asterisk. E.g. foo*-examples.xml or someresource.*, etc.");
System.out.println("-version [ver]: The FHIR version to use. This can only appear once. ");
System.out.println(" valid values 1.0 | 1.4 | 3.0 | " + VersionUtilities.CURRENT_VERSION + " or 1.0.2 | 1.4.0 | 3.0.2 | 4.0.1 | " + VersionUtilities.CURRENT_FULL_VERSION);
System.out.println(" Default value is " + VersionUtilities.CURRENT_VERSION);
System.out.println("-ig [package|file|folder|url]: an IG or profile definition to load. Can be ");
System.out.println(" the URL of an implementation guide or a package ([id]-[ver]) for");
System.out.println(" a built implementation guide or a local folder that contains a");
System.out.println(" set of conformance resources.");
System.out.println(" No default value. This parameter can appear any number of times");
System.out.println("-tx [url]: the [base] url of a FHIR terminology service");
System.out.println(" Default value is http://tx.fhir.org. This parameter can appear once");
System.out.println(" To run without terminology value, specific n/a as the URL");
System.out.println("-txLog [file]: Produce a log of the terminology server operations in [file]");
System.out.println(" Default value is not to produce a log");
System.out.println("-profile [url]: the canonical URL to validate against (same as if it was ");
System.out.println(" specified in Resource.meta.profile). If no profile is specified, the ");
System.out.println(" resource is validated against the base specification. This parameter ");
System.out.println(" can appear any number of times.");
System.out.println(" Note: the profile (and it's dependencies) have to be made available ");
System.out.println(" through one of the -ig parameters. Note that package dependencies will ");
System.out.println(" automatically be resolved");
System.out.println("-questionnaire [file|url}: the location of a questionnaire. If provided, then the validator will validate");
System.out.println(" any QuestionnaireResponse that claims to match the Questionnaire against it");
System.out.println(" no default value. This parameter can appear any number of times");
System.out.println("-output [file]: a filename for the results (OperationOutcome)");
System.out.println(" Default: results are sent to the std out.");
System.out.println("-debug");
System.out.println(" Produce additional information about the loading/validation process");
System.out.println("-recurse");
System.out.println(" Look in subfolders when -ig refers to a folder");
System.out.println("-locale");
System.out.println(" Specifies the locale/language of the validation result messages (eg.: de-DE");
System.out.println("-sct");
System.out.println(" Specify the edition of SNOMED CT to use. Valid Choices:");
System.out.println(" intl | us | uk | au | nl | ca | se | dk | es");
System.out.println(" tx.fhir.org only supports a subset. To add to this list or tx.fhir.org");
System.out.println(" ask on https://chat.fhir.org/#narrow/stream/179202-terminology");
System.out.println("-native: use schema for validation as well");
System.out.println(" * XML: w3c schema+schematron");
System.out.println(" * JSON: json.schema");
System.out.println(" * RDF: SHEX");
System.out.println(" Default: false");
System.out.println("-language: [lang]");
System.out.println(" The language to use when validating coding displays - same value as for xml:lang");
System.out.println(" Not used if the resource specifies language");
System.out.println(" Default: no specified language");
System.out.println("-strictExtensions: If present, treat extensions not defined within the specified FHIR version and any");
System.out.println(" referenced implementation guides or profiles as errors. (Default is to only raise information messages.)");
System.out.println("-hintAboutNonMustSupport: If present, raise hints if the instance contains data elements that are not");
System.out.println(" marked as mustSupport=true. Useful to identify elements included that may be ignored by recipients");
System.out.println("-assumeValidRestReferences: If present, assume that URLs that reference resources follow the RESTful URI pattern");
System.out.println(" and it is safe to infer the type from the URL");
System.out.println("-security-checks: If present, check that string content doesn't include any html-like tags that might create");
System.out.println(" problems downstream (though all external input must always be santized by escaping for either html or sql)");
System.out.println("");
System.out.println("The validator also supports the param -proxy=[address]:[port] for if you use a proxy");
System.out.println("");
System.out.println("Parameters can appear in any order");
System.out.println("");
System.out.println("Alternatively, you can use the validator to execute a transformation as described by a structure map.");
System.out.println("To do this, you must provide some additional parameters:");
System.out.println("");
System.out.println(" -transform [map]");
System.out.println("");
System.out.println("* [map] the URI of the map that the transform starts with");
System.out.println("");
System.out.println("Any other dependency maps have to be loaded through an -ig reference ");
System.out.println("");
System.out.println("-transform uses the parameters -defn, -txserver, -ig (at least one with the map files), and -output");
System.out.println("");
System.out.println("Alternatively, you can use the validator to generate narrative for a resource.");
System.out.println("To do this, you must provide a specific parameter:");
System.out.println("");
System.out.println(" -narrative");
System.out.println("");
System.out.println("-narrative requires the parameters -defn, -txserver, -source, and -output. ig and profile may be used");
System.out.println("");
System.out.println("Alternatively, you can use the validator to convert a resource or logical model.");
System.out.println("To do this, you must provide a specific parameter:");
System.out.println("");
System.out.println(" -convert");
System.out.println("");
System.out.println("-convert requires the parameters -source and -output. ig may be used to provide a logical model");
System.out.println("");
System.out.println("Alternatively, you can use the validator to evaluate a FHIRPath expression on a resource or logical model.");
System.out.println("To do this, you must provide a specific parameter:");
System.out.println("");
System.out.println(" -fhirpath [FHIRPath]");
System.out.println("");
System.out.println("* [FHIRPath] the FHIRPath expression to evaluate");
System.out.println("");
System.out.println("-fhirpath requires the parameters -source. ig may be used to provide a logical model");
System.out.println("");
System.out.println("Finally, you can use the validator to generate a snapshot for a profile.");
System.out.println("To do this, you must provide a specific parameter:");
System.out.println("");
System.out.println(" -snapshot");
System.out.println("");
System.out.println("-snapshot requires the parameters -defn, -txserver, -source, and -output. ig may be used to provide necessary base profiles");
} }
/**
* Prints out system info to the command line.
*/
public static void displaySystemInfo() {
System.out.println(" Java: " + System.getProperty("java.version")
+ " from " + System.getProperty("java.home")
+ " on " + System.getProperty("os.arch")
+ " (" + System.getProperty("sun.arch.data.model") + "bit). "
+ toMB(Runtime.getRuntime().maxMemory()) + "MB available");
}
/**
* Prints current version of the validator.
*/
public static void displayVersion() {
System.out.println("FHIR Validation tool " + VersionUtil.getVersionString());
}
} }

View File

@ -0,0 +1,4 @@
package org.hl7.fhir.validation.cli.utils;
public enum EngineMode {
VALIDATION, TRANSFORM, NARRATIVE, SNAPSHOT, SCAN, CONVERT, FHIRPATH, VERSION
}

View File

@ -6,12 +6,10 @@ import java.util.Locale;
import org.hl7.fhir.r5.utils.IResourceValidator.BundleValidationRule; import org.hl7.fhir.r5.utils.IResourceValidator.BundleValidationRule;
import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.validation.Validator;
import org.hl7.fhir.validation.cli.model.CliContext; import org.hl7.fhir.validation.cli.model.CliContext;
public class Params { public class Params {
public static final String GUI = "-gui";
public static final String VERSION = "-version"; public static final String VERSION = "-version";
public static final String OUTPUT = "-output"; public static final String OUTPUT = "-output";
public static final String PROXY = "-proxy"; public static final String PROXY = "-proxy";
@ -74,9 +72,9 @@ public class Params {
* @return {@link String} value for the provided param. * @return {@link String} value for the provided param.
*/ */
public static String getParam(String[] args, String param) { public static String getParam(String[] args, String param) {
for (int i = 0; i < args.length - 1; i++) for (int i = 0; i < args.length - 1; i++) {
if (args[i].equals(param)) if (args[i].equals(param)) return args[i + 1];
return args[i + 1]; }
return null; return null;
} }
@ -104,7 +102,7 @@ public class Params {
} else { } else {
p = args[++i]; p = args[++i];
cliContext.addProfile(p); cliContext.addProfile(p);
} }
} else if (args[i].equals(BUNDLE)) { } else if (args[i].equals(BUNDLE)) {
String p = null; String p = null;
String r = null; String r = null;
@ -124,7 +122,7 @@ public class Params {
throw new Error("Specified -questionnaire without indicating questionnaire file"); throw new Error("Specified -questionnaire without indicating questionnaire file");
else { else {
String q = args[++i]; String q = args[++i];
cliContext.setQuestionnaireMode(Validator.QuestionnaireMode.valueOf(q)); cliContext.setQuestionnaireMode(QuestionnaireMode.valueOf(q));
} }
} else if (args[i].equals(NATIVE)) { } else if (args[i].equals(NATIVE)) {
cliContext.setDoNative(true); cliContext.setDoNative(true);
@ -145,25 +143,25 @@ public class Params {
} else if (args[i].equals(STRICT_EXTENSIONS)) { } else if (args[i].equals(STRICT_EXTENSIONS)) {
cliContext.setAnyExtensionsAllowed(false); cliContext.setAnyExtensionsAllowed(false);
} else if (args[i].equals(NO_INTERNAL_CACHING)) { } else if (args[i].equals(NO_INTERNAL_CACHING)) {
cliContext.setNoInternalCaching(true); cliContext.setNoInternalCaching(true);
} else if (args[i].equals(NO_EXTENSIBLE_BINDING_WARNINGS)) { } else if (args[i].equals(NO_EXTENSIBLE_BINDING_WARNINGS)) {
cliContext.setNoExtensibleBindingMessages(true); cliContext.setNoExtensibleBindingMessages(true);
} else if (args[i].equals(HINT_ABOUT_NON_MUST_SUPPORT)) { } else if (args[i].equals(HINT_ABOUT_NON_MUST_SUPPORT)) {
cliContext.setHintAboutNonMustSupport(true); cliContext.setHintAboutNonMustSupport(true);
} else if (args[i].equals(TO_VERSION)) { } else if (args[i].equals(TO_VERSION)) {
cliContext.setTargetVer(args[++i]); cliContext.setTargetVer(args[++i]);
cliContext.setMode(Validator.EngineMode.VERSION); cliContext.setMode(EngineMode.VERSION);
} else if (args[i].equals(DO_NATIVE)) { } else if (args[i].equals(DO_NATIVE)) {
cliContext.setCanDoNative(true); cliContext.setCanDoNative(true);
} else if (args[i].equals(NO_NATIVE)) { } else if (args[i].equals(NO_NATIVE)) {
cliContext.setCanDoNative(false); cliContext.setCanDoNative(false);
} else if (args[i].equals(TRANSFORM)) { } else if (args[i].equals(TRANSFORM)) {
cliContext.setMap(args[++i]); cliContext.setMap(args[++i]);
cliContext.setMode(Validator.EngineMode.TRANSFORM); cliContext.setMode(EngineMode.TRANSFORM);
} else if (args[i].equals(NARRATIVE)) { } else if (args[i].equals(NARRATIVE)) {
cliContext.setMode(Validator.EngineMode.NARRATIVE); cliContext.setMode(EngineMode.NARRATIVE);
} else if (args[i].equals(SNAPSHOT)) { } else if (args[i].equals(SNAPSHOT)) {
cliContext.setMode(Validator.EngineMode.SNAPSHOT); cliContext.setMode(EngineMode.SNAPSHOT);
} else if (args[i].equals(SECURITY_CHECKS)) { } else if (args[i].equals(SECURITY_CHECKS)) {
cliContext.setSecurityChecks(true); cliContext.setSecurityChecks(true);
} else if (args[i].equals(CRUMB_TRAIL)) { } else if (args[i].equals(CRUMB_TRAIL)) {
@ -171,7 +169,7 @@ public class Params {
} else if (args[i].equals(SHOW_TIMES)) { } else if (args[i].equals(SHOW_TIMES)) {
cliContext.setShowTimes(true); cliContext.setShowTimes(true);
} else if (args[i].equals(SCAN)) { } else if (args[i].equals(SCAN)) {
cliContext.setMode(Validator.EngineMode.SCAN); cliContext.setMode(EngineMode.SCAN);
} else if (args[i].equals(TERMINOLOGY)) { } else if (args[i].equals(TERMINOLOGY)) {
if (i + 1 == args.length) if (i + 1 == args.length)
throw new Error("Specified -tx without indicating terminology server"); throw new Error("Specified -tx without indicating terminology server");
@ -216,9 +214,9 @@ public class Params {
} else if (args[i].startsWith(X)) { } else if (args[i].startsWith(X)) {
i++; i++;
} else if (args[i].equals(CONVERT)) { } else if (args[i].equals(CONVERT)) {
cliContext.setMode(Validator.EngineMode.CONVERT); cliContext.setMode(EngineMode.CONVERT);
} else if (args[i].equals(FHIRPATH)) { } else if (args[i].equals(FHIRPATH)) {
cliContext.setMode(Validator.EngineMode.FHIRPATH); cliContext.setMode(EngineMode.FHIRPATH);
if (cliContext.getFhirpath() == null) if (cliContext.getFhirpath() == null)
if (i + 1 == args.length) if (i + 1 == args.length)
throw new Error("Specified -fhirpath without indicating a FHIRPath expression"); throw new Error("Specified -fhirpath without indicating a FHIRPath expression");

View File

@ -0,0 +1,3 @@
package org.hl7.fhir.validation.cli.utils;
public enum QuestionnaireMode { NONE, CHECK, REQUIRED }

View File

@ -0,0 +1,41 @@
package org.hl7.fhir.validation.cli.utils;
import org.hl7.fhir.utilities.VersionUtilities;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class VersionSourceInformation {
private List<String> report = new ArrayList<>();
private List<String> versions = new ArrayList<>();
public void see(String version, String src) {
version = VersionUtilities.getMajMin(version);
report.add(src+": "+version);
if (!versions.contains(version)) {
versions.add(version);
Collections.sort(versions);
}
}
public boolean isEmpty() {
return versions.isEmpty();
}
public int size() {
return versions.size();
}
public String version() {
return versions.get(0);
}
public List<String> getReport() {
if (report.isEmpty()) {
report.add("(nothing found)");
}
return report;
}
}

View File

@ -147,7 +147,7 @@ import org.hl7.fhir.utilities.validation.ValidationOptions;
import org.hl7.fhir.utilities.xhtml.NodeType; import org.hl7.fhir.utilities.xhtml.NodeType;
import org.hl7.fhir.utilities.xhtml.XhtmlNode; import org.hl7.fhir.utilities.xhtml.XhtmlNode;
import org.hl7.fhir.validation.BaseValidator; import org.hl7.fhir.validation.BaseValidator;
import org.hl7.fhir.validation.Validator.QuestionnaireMode; import org.hl7.fhir.validation.cli.utils.QuestionnaireMode;
import org.hl7.fhir.validation.instance.type.BundleValidator; import org.hl7.fhir.validation.instance.type.BundleValidator;
import org.hl7.fhir.validation.instance.type.CodeSystemValidator; import org.hl7.fhir.validation.instance.type.CodeSystemValidator;
import org.hl7.fhir.validation.instance.type.MeasureValidator; import org.hl7.fhir.validation.instance.type.MeasureValidator;

View File

@ -43,8 +43,8 @@ import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
import org.hl7.fhir.utilities.validation.ValidationMessage.Source; import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
import org.hl7.fhir.utilities.validation.ValidationOptions; import org.hl7.fhir.utilities.validation.ValidationOptions;
import org.hl7.fhir.validation.BaseValidator; import org.hl7.fhir.validation.BaseValidator;
import org.hl7.fhir.validation.cli.utils.QuestionnaireMode;
import org.hl7.fhir.validation.TimeTracker; import org.hl7.fhir.validation.TimeTracker;
import org.hl7.fhir.validation.Validator.QuestionnaireMode;
import org.hl7.fhir.validation.instance.EnableWhenEvaluator; import org.hl7.fhir.validation.instance.EnableWhenEvaluator;
import org.hl7.fhir.validation.instance.EnableWhenEvaluator.QStack; import org.hl7.fhir.validation.instance.EnableWhenEvaluator.QStack;
import org.hl7.fhir.validation.instance.utils.NodeStack; import org.hl7.fhir.validation.instance.utils.NodeStack;
@ -86,7 +86,6 @@ public class QuestionnaireValidator extends BaseValidator {
} }
} }
private void validateQuestionnaireElement(List<ValidationMessage> errors, NodeStack ns, Element questionnaire, Element item, List<Element> parents) { private void validateQuestionnaireElement(List<ValidationMessage> errors, NodeStack ns, Element questionnaire, Element item, List<Element> parents) {
// R4+ // R4+
if ((FHIRVersion.isR4Plus(context.getVersion())) && (item.hasChildren("enableWhen"))) { if ((FHIRVersion.isR4Plus(context.getVersion())) && (item.hasChildren("enableWhen"))) {

View File

@ -0,0 +1,121 @@
The FHIR validation tool validates a FHIR resource or bundle.
The validation tool compares a resource against the base definitions and any
profiles declared in the resource (Resource.meta.profile) or specified on the
command line
The FHIR validation tool validates a FHIR resource or bundle.
Schema and schematron checking is performed, then some additional checks are performed.
* XML & Json (FHIR versions 1.0, 1.4, 3.0, 4.0, " + Constants.VERSION_MM + ")
* Turtle (FHIR versions 3.0, 4.0, " + Constants.VERSION_MM + ")
If requested, instances will also be verified against the appropriate schema
W3C XML Schema, JSON schema or ShEx, as appropriate
Usage: java -jar [validator].jar (parameters)
The following parameters are supported:
[source]: a file, url, directory or pattern for resources to validate. At
least one source must be declared. If there is more than one source or if
the source is other than a single file or url and the output parameter is
used, results will be provided as a Bundle.
Patterns are limited to a directory followed by a filename with an embedded
asterisk. E.g. foo*-examples.xml or someresource.*, etc.
-version [ver]: The FHIR version to use. This can only appear once.
valid values 1.0 | 1.4 | 3.0 | " + VersionUtilities.CURRENT_VERSION + " or 1.0.2 | 1.4.0 | 3.0.2 | 4.0.1 | " + VersionUtilities.CURRENT_FULL_VERSION);
Default value is " + VersionUtilities.CURRENT_VERSION);
-ig [package|file|folder|url]: an IG or profile definition to load. Can be
the URL of an implementation guide or a package ([id]-[ver]) for
a built implementation guide or a local folder that contains a
set of conformance resources.
No default value. This parameter can appear any number of times
-tx [url]: the [base] url of a FHIR terminology service
Default value is http://tx.fhir.org. This parameter can appear once
To run without terminology value, specific n/a as the URL
-txLog [file]: Produce a log of the terminology server operations in [file]
Default value is not to produce a log
-profile [url]: the canonical URL to validate against (same as if it was
specified in Resource.meta.profile). If no profile is specified, the
resource is validated against the base specification. This parameter
can appear any number of times.
Note: the profile (and it's dependencies) have to be made available
through one of the -ig parameters. Note that package dependencies will
automatically be resolved
-questionnaire [file|url}: the location of a questionnaire. If provided, then the validator will validate
any QuestionnaireResponse that claims to match the Questionnaire against it
no default value. This parameter can appear any number of times
-output [file]: a filename for the results (OperationOutcome)
Default: results are sent to the std out.
-debug
Produce additional information about the loading/validation process
-recurse
Look in subfolders when -ig refers to a folder
-locale
Specifies the locale/language of the validation result messages (eg.: de-DE
-sct
Specify the edition of SNOMED CT to use. Valid Choices:
intl | us | uk | au | nl | ca | se | dk | es
tx.fhir.org only supports a subset. To add to this list or tx.fhir.org
ask on https://chat.fhir.org/#narrow/stream/179202-terminology
-native: use schema for validation as well
* XML: w3c schema+schematron
* JSON: json.schema
* RDF: SHEX
Default: false
-language: [lang]
The language to use when validating coding displays - same value as for xml:lang
Not used if the resource specifies language
Default: no specified language
-strictExtensions: If present, treat extensions not defined within the specified FHIR version and any
referenced implementation guides or profiles as errors. (Default is to only raise information messages.)
-hintAboutNonMustSupport: If present, raise hints if the instance contains data elements that are not
marked as mustSupport=true. Useful to identify elements included that may be ignored by recipients
-assumeValidRestReferences: If present, assume that URLs that reference resources follow the RESTful URI pattern
and it is safe to infer the type from the URL
-security-checks: If present, check that string content doesn't include any html-like tags that might create
problems downstream (though all external input must always be santized by escaping for either html or sql)
The validator also supports the param -proxy=[address]:[port] for if you use a proxy
Parameters can appear in any order
Alternatively, you can use the validator to execute a transformation as described by a structure map.
To do this, you must provide some additional parameters:
-transform [map]
* [map] the URI of the map that the transform starts with
Any other dependency maps have to be loaded through an -ig reference
-transform uses the parameters -defn, -txserver, -ig (at least one with the map files), and -output
Alternatively, you can use the validator to generate narrative for a resource.
To do this, you must provide a specific parameter:
-narrative
-narrative requires the parameters -defn, -txserver, -source, and -output. ig and profile may be used
Alternatively, you can use the validator to convert a resource or logical model.
To do this, you must provide a specific parameter:
-convert
-convert requires the parameters -source and -output. ig may be used to provide a logical model
Alternatively, you can use the validator to evaluate a FHIRPath expression on a resource or logical model.
To do this, you must provide a specific parameter:
-fhirpath [FHIRPath]
* [FHIRPath] the FHIRPath expression to evaluate
-fhirpath requires the parameters -source. ig may be used to provide a logical model
Finally, you can use the validator to generate a snapshot for a profile.
To do this, you must provide a specific parameter:
-snapshot
-snapshot requires the parameters -defn, -txserver, -source, and -output. ig may be used to provide necessary base profiles

View File

@ -1,37 +0,0 @@
package org.hl7.fhir.validation.cli;
import java.io.IOException;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.hl7.fhir.validation.cli.model.CliContext;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
public abstract class BaseRestTest {
protected final String JSON_MIME_TYPE = "application/json";
@BeforeAll
public static void startServer() {
ValidatorGui.start(new CliContext(), null, false);
}
@AfterAll
public static void stopServer() {
ValidatorGui.stop();
}
public static <T> T retrieveResourceFromResponse(HttpResponse response, Class<T> clazz)
throws IOException {
String jsonFromResponse = EntityUtils.toString(response.getEntity());
ObjectMapper mapper = new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return mapper.readValue(jsonFromResponse, clazz);
}
}

View File

@ -1,35 +0,0 @@
package org.hl7.fhir.validation.cli;
import java.io.IOException;
import org.hl7.fhir.validation.cli.model.CliContext;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import io.github.bonigarcia.wdm.WebDriverManager;
class ValidatorGuiTest {
private static final String DEF_TX = "http://tx.fhir.org";
private final String HTML_TITLE_TAG = "<title>FHIR HL7 Resrouce Validator GUI</title>";
@Test
@DisplayName("Page boots correctly, and displays index.html")
public void UI_contains_correct_heading() throws IOException {
ValidatorGui.start(new CliContext(), null, false);
WebDriverManager.chromedriver().setup();
ChromeOptions options = new ChromeOptions();
options.addArguments("--headless");
options.addArguments("--disable-gpu");
WebDriver driver = new ChromeDriver(options);
driver.get("http://localhost:" + ValidatorGui.getPort() + "/home");
Assertions.assertTrue(driver.getPageSource().contains(HTML_TITLE_TAG));
driver.quit();
ValidatorGui.stop();
}
}

View File

@ -1,48 +0,0 @@
package org.hl7.fhir.validation.cli.controller;
import java.io.IOException;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.HttpClientBuilder;
import org.hl7.fhir.validation.cli.BaseRestTest;
import org.hl7.fhir.validation.cli.ValidatorGui;
import org.hl7.fhir.validation.cli.model.CliContext;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
class HttpGetContextTest extends BaseRestTest {
private final String GET_CONTEXT_URL = "http://localhost:" + ValidatorGui.getPort() + "/context";
@Test
@DisplayName("Testing status code on get context endpoint.")
public void testStatus() throws IOException {
HttpUriRequest request = new HttpGet(GET_CONTEXT_URL);
HttpResponse httpResponse = HttpClientBuilder.create().build().execute(request);
Assertions.assertEquals(httpResponse.getStatusLine().getStatusCode(), HttpStatus.SC_OK);
}
@Test
@DisplayName("Testing media type on get context endpoint.")
public void testMediaType() throws IOException {
HttpUriRequest request = new HttpGet(GET_CONTEXT_URL);
HttpResponse httpResponse = HttpClientBuilder.create().build().execute(request);
String mimeType = ContentType.getOrDefault(httpResponse.getEntity()).getMimeType();
Assertions.assertEquals(JSON_MIME_TYPE, mimeType );
}
@Test
@DisplayName("Testing status code on get context endpoint.")
public void testJSONPayload() throws IOException {
HttpUriRequest request = new HttpGet(GET_CONTEXT_URL);
HttpResponse httpResponse = HttpClientBuilder.create().build().execute(request);
CliContext resource = retrieveResourceFromResponse(httpResponse, CliContext.class);
Assertions.assertEquals(new CliContext(), resource);
}
}

View File

@ -1,26 +0,0 @@
package org.hl7.fhir.validation.cli.controller;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import io.javalin.http.Context;
class HttpPutContextTest {
public CliContextController myCliContextController;
public HttpPutContextTest() {
this.myCliContextController = new CliContextController(null);
}
@Disabled
@Test
void handleSetCurrentCliContext() {
Context context = mock(Context.class);
this.myCliContextController.handleSetCurrentCliContext(context);
verify(context).status(200);
}
}