From b0a15a11a2936cec9ad79a60339d0e2a3c927a8d Mon Sep 17 00:00:00 2001 From: markiantorno Date: Thu, 2 Apr 2020 11:40:44 -0400 Subject: [PATCH 1/4] Cleaning up cli code --- .../org/hl7/fhir/validation/Validator.java | 480 ++++-------------- .../fhir/validation/cliutils/CliContext.java | 4 + .../validation/cliutils/ComparisonUtils.java | 98 ++++ .../validation/cliutils/DisplayUtils.java | 143 ++++++ .../fhir/validation/cliutils/ParamUtils.java | 33 ++ .../hl7/fhir/validation/cliutils/Utils.java | 129 +++++ .../tests/ValidationEngineTests.java | 19 - 7 files changed, 517 insertions(+), 389 deletions(-) create mode 100644 org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/CliContext.java create mode 100644 org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ComparisonUtils.java create mode 100644 org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/DisplayUtils.java create mode 100644 org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ParamUtils.java create mode 100644 org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Utils.java diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Validator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Validator.java index e69c96e96..edab6776a 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Validator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Validator.java @@ -9,9 +9,9 @@ package org.hl7.fhir.validation; * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -51,6 +51,7 @@ POSSIBILITY OF SUCH DAMAGE. import java.awt.Desktop; import java.io.File; import java.io.FileOutputStream; +import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -63,6 +64,7 @@ import java.util.UUID; import org.hl7.fhir.r5.conformance.CapabilityStatementUtilities; import org.hl7.fhir.r5.conformance.CapabilityStatementUtilities.CapabilityStatementComparisonOutput; import org.hl7.fhir.r5.conformance.ProfileComparer; +import org.hl7.fhir.r5.context.SimpleWorkerContext; import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat; import org.hl7.fhir.r5.formats.IParser; import org.hl7.fhir.r5.formats.IParser.OutputStyle; @@ -71,7 +73,6 @@ import org.hl7.fhir.r5.formats.JsonParser; import org.hl7.fhir.r5.model.Bundle; import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent; import org.hl7.fhir.r5.model.CapabilityStatement; -import org.hl7.fhir.r5.model.Constants; import org.hl7.fhir.r5.model.DomainResource; import org.hl7.fhir.r5.model.FhirPublication; import org.hl7.fhir.r5.model.ImplementationGuide; @@ -86,23 +87,24 @@ import org.hl7.fhir.validation.ValidationEngine.ScanOutputItem; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; -import org.hl7.fhir.utilities.cache.PackageCacheManager; -import org.hl7.fhir.utilities.cache.ToolsVersion; import org.hl7.fhir.utilities.validation.ValidationMessage; +import org.hl7.fhir.validation.cliutils.ComparisonUtils; +import org.hl7.fhir.validation.cliutils.DisplayUtils; +import org.hl7.fhir.validation.cliutils.ParamUtils; +import org.hl7.fhir.validation.cliutils.Utils; /** * A executable class that will validate one or more FHIR resources against * the specification - * + *

* todo: schema validation (w3c xml, json schema, shex?) - * + *

* if you want to host validation inside a process, skip this class, and look at * ValidationEngine - * + *

* todo: find a gome for this: - - * @author Grahame * + * @author Grahame */ public class Validator { @@ -123,12 +125,12 @@ public class Validator { } private static String toMB(long maxMemory) { - return Long.toString(maxMemory / (1024*1024)); + return Long.toString(maxMemory / (1024 * 1024)); } public static void main(String[] args) throws Exception { System.out.println("FHIR Validation tool " + VersionUtil.getVersionString()); - System.out.println("Detected Java version: " + 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"); + System.out.println("Detected Java version: " + 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"); String proxy = getNamedParam(args, "-proxy"); if (!Utilities.noString(proxy)) { String[] p = proxy.split("\\:"); @@ -136,263 +138,26 @@ public class Validator { System.setProperty("http.proxyPort", p[1]); } - if (hasParam(args, "-tests")) { - try { - Class clazz = Class.forName("org.hl7.fhir.validation.r5.tests.ValidationEngineTests"); - clazz.getMethod("execute").invoke(clazz); - } catch (Exception e) { - e.printStackTrace(); - } - } else if (args.length == 0 || hasParam(args, "help") || hasParam(args, "?") || hasParam(args, "-?") || hasParam(args, "/?") ) { - System.out.println(""); - System.out.println("The FHIR validation tool validates a FHIR resource or bundle."); - System.out.println("The validation tool compares a resource against the base definitions and any"); - System.out.println("profiles declared in the resource (Resource.meta.profile) or specified on the "); - System.out.println("command line"); - System.out.println(""); - System.out.println("The FHIR validation tool validates a FHIR resource or bundle."); - 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(""); - 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"); - } else if (hasParam(args, "-compare")) { - System.out.print("Arguments:"); - for (String s : args) - System.out.print(s.contains(" ") ? " \""+s+"\"" : " "+s); - System.out.println(); - System.out.println("Directories: Current = "+System.getProperty("user.dir")+", Package Cache = "+new PackageCacheManager(true, ToolsVersion.TOOLS_VERSION).getFolder()); - - String dest = getParam(args, "-dest"); + if (ParamUtils.hasParam(args, "-tests")) { + Utils.runValidationEngineTests(); + } else if (args.length == 0 || ParamUtils.hasParam(args, "help") || ParamUtils.hasParam(args, "?") || ParamUtils.hasParam(args, "-?") || ParamUtils.hasParam(args, "/?")) { + DisplayUtils.displayHelpDetails(); + } else if (ParamUtils.hasParam(args, "-compare")) { + DisplayUtils.printCliArgumentsAndInfo(args); + String dest = ParamUtils.getParam(args, "-dest"); 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+"\")"); + System.out.println("Specified destination (-dest parameter) is not valid: \"" + dest + "\")"); else { // first, prepare the context - String txLog = null; - if (hasParam(args, "-txLog")) { - txLog = getParam(args, "-txLog"); - new File(txLog).delete(); - } - String v = getParam(args, "-version"); - if (v == null) { - v = "current"; - for (int i = 0; i < args.length; i++) { - if ("-ig".equals(args[i])) { - if (i+1 == args.length) - throw new Error("Specified -ig without indicating ig file"); - else { - String n = args[i+1]; - if (n.startsWith("hl7.fhir.core#")) { - v = VersionUtilities.getCurrentPackageVersion(n.substring(14)); - } else if (n.startsWith("hl7.fhir.r2.core#") || n.equals("hl7.fhir.r2.core")) { - v = "1.0"; - } else if (n.startsWith("hl7.fhir.r2b.core#") || n.equals("hl7.fhir.r2b.core")) { - v = "1.4"; - } else if (n.startsWith("hl7.fhir.r3.core#") || n.equals("hl7.fhir.r3.core")) { - v = "3.0"; - } else if (n.startsWith("hl7.fhir.r4.core#") || n.equals("hl7.fhir.r4.core")) { - v = "4.0"; - } else if (n.startsWith("hl7.fhir.r5.core#") || n.equals("hl7.fhir.r5.core")) { - v = "current"; - } - } - } - } - } else if ("1.0".equals(v)) { - v = "1.0"; - } else if ("1.4".equals(v)) { - v = "1.4"; - } else if ("3.0".equals(v)) { - v = "3.0"; - } else if ("4.0".equals(v)) { - v = "4.0"; - } else if (v.startsWith(Constants.VERSION)) { - v = "current"; - } - String definitions = VersionUtilities.packageForVersion(v)+"#"+v; - System.out.println("Loading (v = "+v+", tx server http://tx.fhir.org)"); - ValidationEngine validator = new ValidationEngine(definitions, "http://tx.fhir.org", txLog, FhirPublication.fromCode(v), v); - for (int i = 0; i < args.length; i++) { - if ("-ig".equals(args[i])) { - if (i+1 == args.length) - throw new Error("Specified -ig without indicating ig file"); - else { - String s = args[++i]; - if (!s.startsWith("hl7.fhir.core-")) { - System.out.println("Load Package: "+s); - } - } - } - } - // ok now set up the comparison - String left = getParam(args, "-left"); - String right = getParam(args, "-right"); - Resource resLeft = validator.getContext().fetchResource(Resource.class, left); - Resource resRight = validator.getContext().fetchResource(Resource.class, right); - if (resLeft == null) { - System.out.println("Unable to locate left resource " +left); - } - if (resRight == null) { - System.out.println("Unable to locate right resource " +right); - } - if (resLeft != null && resRight != null) { - if (resLeft instanceof StructureDefinition && resRight instanceof StructureDefinition) { - System.out.println("Comparing StructureDefinitions "+left+" to "+right); - ProfileComparer pc = new ProfileComparer(validator.getContext(), dest); - StructureDefinition sdL = (StructureDefinition) resLeft; - StructureDefinition sdR = (StructureDefinition) resRight; - pc.compareProfiles(sdL, sdR); - System.out.println("Generating output to "+dest+"..."); - File htmlFile = new File(pc.generate()); - Desktop.getDesktop().browse(htmlFile.toURI()); - System.out.println("Done"); - } else if (resLeft instanceof CapabilityStatement && resRight instanceof CapabilityStatement) { - String nameLeft = chooseName(args, "leftName", (CanonicalResource) resLeft); - String nameRight = chooseName(args, "rightName", (CanonicalResource) resRight); - System.out.println("Comparing CapabilityStatements "+left+" to "+right); - CapabilityStatementUtilities pc = new CapabilityStatementUtilities(validator.getContext(), dest, new KeyGenerator("http://fhir.org/temp/"+UUID.randomUUID().toString().toLowerCase())); - CapabilityStatement capL = (CapabilityStatement) resLeft; - CapabilityStatement capR = (CapabilityStatement) resRight; - CapabilityStatementComparisonOutput output = pc.isCompatible(nameLeft, nameRight, capL, capR); - - String destTxt = Utilities.path(dest, "output.txt"); - System.out.println("Generating output to "+destTxt+"..."); - StringBuilder b = new StringBuilder(); - for (ValidationMessage msg : output.getMessages()) { - b.append(msg.summary()); - b.append("\r\n"); - } - TextFile.stringToFile(b.toString(), destTxt); - new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(dest, "CapabilityStatement-union.xml")), output.getSuperset()); - new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(dest, "CapabilityStatement-intersection.xml")), output.getSubset()); - new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(dest, "OperationOutcome-issues.xml")), output.getOutcome()); - new JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(dest, "CapabilityStatement-union.json")), output.getSuperset()); - new JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(dest, "CapabilityStatement-intersection.json")), output.getSubset()); - new JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(dest, "OperationOutcome-issues.json")), output.getOutcome()); - - String destHtml = Utilities.path(dest, "index.html"); - File htmlFile = new File(destHtml); - Desktop.getDesktop().browse(htmlFile.toURI()); - System.out.println("Done"); - } else - System.out.println("Unable to compare left resource " +left+" ("+resLeft.fhirType()+") with right resource "+right+" ("+resRight.fhirType()+")"); - } + String txLog = Utils.getTerminologyServerLog(args); + ValidationEngine validator = Utils.getValidationEngine(args, txLog); + Utils.checkIGFileReferences(args); + ComparisonUtils.doLeftRightComparison(args, dest, validator); } } else { - System.out.print("Arguments:"); - for (String s : args) - System.out.print(s.contains(" ") ? " \""+s+"\"" : " "+s); - System.out.println(); - System.out.println("Directories: Current = "+System.getProperty("user.dir")+", Package Cache = "+new PackageCacheManager(true, ToolsVersion.TOOLS_VERSION).getFolder()); + DisplayUtils.printCliArgumentsAndInfo(args); String map = null; List igs = new ArrayList(); @@ -407,7 +172,7 @@ public class Validator { EngineMode mode = EngineMode.VALIDATION; String output = null; Boolean canDoNative = null; - List sources= new ArrayList(); + List sources = new ArrayList(); Map locations = new HashMap(); String sv = "current"; String txLog = null; @@ -421,11 +186,11 @@ public class Validator { // load the parameters - so order doesn't matter for (int i = 0; i < args.length; i++) { - if (args[i].equals("-version")) { + if (args[i].equals("-version")) { sv = args[++i]; sv = VersionUtilities.getCurrentPackageVersion(sv); } else if (args[i].equals("-output")) { - if (i+1 == args.length) + if (i + 1 == args.length) throw new Error("Specified -output without indicating output file"); else output = args[++i]; @@ -433,56 +198,37 @@ public class Validator { i++; // ignore next parameter } else if (args[i].equals("-profile")) { String p = null; - if (i+1 == args.length) + if (i + 1 == args.length) throw new Error("Specified -profile without indicating profile source"); else { p = args[++i]; profiles.add(p); } - if (p != null && i+1 < args.length && args[i+1].equals("@")) { + if (p != null && i + 1 < args.length && args[i + 1].equals("@")) { i++; - if (i+1 == args.length) + if (i + 1 == args.length) throw new Error("Specified -profile with @ without indicating profile location"); else locations.put(p, args[++i]); } } else if (args[i].equals("-questionnaire")) { - if (i+1 == args.length) + if (i + 1 == args.length) throw new Error("Specified -questionnaire without indicating questionnaire file"); else questionnaires.add(args[++i]); } else if (args[i].equals("-native")) { - doNative = true; + doNative = true; } else if (args[i].equals("-assumeValidRestReferences")) { - assumeValidRestReferences = true; + assumeValidRestReferences = true; } else if (args[i].equals("-debug")) { doDebug = true; } else if (args[i].equals("-sct")) { String s = args[++i]; - if ("intl".equalsIgnoreCase(s)) - snomedCT = "900000000000207008"; - else if ("us".equalsIgnoreCase(s)) - snomedCT = "731000124108"; - else if ("uk".equalsIgnoreCase(s)) - snomedCT = "999000041000000102"; - else if ("au".equalsIgnoreCase(s)) - snomedCT = "32506021000036107"; - else if ("ca".equalsIgnoreCase(s)) - snomedCT = "20611000087101"; - else if ("nl".equalsIgnoreCase(s)) - snomedCT = "11000146104"; - else if ("se".equalsIgnoreCase(s)) - snomedCT = "45991000052106"; - else if ("es".equalsIgnoreCase(s)) - snomedCT = "449081005"; - else if ("dk".equalsIgnoreCase(s)) - snomedCT = "554471000005108"; - else - throw new Error("Snomed edition '"+s+"' not known"); + snomedCT = resolveSnomedCTCode(s); } else if (args[i].equals("-recurse")) { recursive = true; } else if (args[i].equals("-locale")) { - if (i+1 == args.length) { + if (i + 1 == args.length) { throw new Error("Specified -locale without indicating locale"); } else { locale = new Locale(args[++i]); @@ -508,28 +254,28 @@ public class Validator { } else if (args[i].equals("-scan")) { mode = EngineMode.SCAN; } else if (args[i].equals("-tx")) { - if (i+1 == args.length) + if (i + 1 == args.length) throw new Error("Specified -tx without indicating terminology server"); else txServer = "n/a".equals(args[++i]) ? null : args[i]; } else if (args[i].equals("-txLog")) { - if (i+1 == args.length) + if (i + 1 == args.length) throw new Error("Specified -txLog without indicating file"); else txLog = args[++i]; } else if (args[i].equals("-log")) { - if (i+1 == args.length) + if (i + 1 == args.length) throw new Error("Specified -log without indicating file"); else mapLog = args[++i]; } else if (args[i].equals("-language")) { - if (i+1 == args.length) + if (i + 1 == args.length) throw new Error("Specified -language without indicating language"); else lang = args[++i]; } else if (args[i].equals("-ig") || args[i].equals("-defn")) { - if (i+1 == args.length) - throw new Error("Specified "+args[i]+" without indicating ig file"); + if (i + 1 == args.length) + throw new Error("Specified " + args[i] + " without indicating ig file"); else { String s = args[++i]; if (s.equals("hl7.fhir.core")) { @@ -546,13 +292,12 @@ public class Validator { sv = "4.0"; } else if (s.startsWith("hl7.fhir.r5.core#") || s.equals("hl7.fhir.r5.core")) { sv = "current"; - } - else + } else igs.add(s); } } else if (args[i].equals("-map")) { if (map == null) { - if (i+1 == args.length) + if (i + 1 == args.length) throw new Error("Specified -map without indicating map file"); else map = args[++i]; @@ -564,30 +309,30 @@ public class Validator { } else if (args[i].equals("-convert")) { mode = EngineMode.CONVERT; } else if (args[i].equals("-fhirpath")) { - mode = EngineMode.FHIRPATH; - if (fhirpath == null) - if (i+1 == args.length) - throw new Error("Specified -fhirpath without indicating a FHIRPath expression"); - else - fhirpath = args[++i]; + mode = EngineMode.FHIRPATH; + if (fhirpath == null) + if (i + 1 == args.length) + throw new Error("Specified -fhirpath without indicating a FHIRPath expression"); else - throw new Exception("Can only nominate a single -fhirpath parameter"); + fhirpath = args[++i]; + else + throw new Exception("Can only nominate a single -fhirpath parameter"); } else { sources.add(args[i]); } } - if (sources.isEmpty()) + if (sources.isEmpty()) throw new Exception("Must provide at least one source file"); // 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(sv)+"#"+VersionUtilities.getCurrentVersion(sv); - System.out.println(" .. FHIR Version "+sv+", definitions from "+definitions); - System.out.println(" .. connect to tx server @ "+txServer); + String definitions = VersionUtilities.packageForVersion(sv) + "#" + VersionUtilities.getCurrentVersion(sv); + System.out.println(" .. FHIR Version " + sv + ", definitions from " + definitions); + System.out.println(" .. connect to tx server @ " + txServer); ValidationEngine validator = new ValidationEngine(definitions, txServer, txLog, FhirPublication.fromCode(sv), sv); validator.setDebug(doDebug); - System.out.println(" (v"+validator.getContext().getVersion()+")"); + System.out.println(" (v" + validator.getContext().getVersion() + ")"); for (String src : igs) { - System.out.println("+ .. load IG from "+src); + System.out.println("+ .. load IG from " + src); validator.loadIg(src, recursive); } validator.setQuestionnaires(questionnaires); @@ -607,10 +352,10 @@ public class Validator { x.setOutputStyle(OutputStyle.PRETTY); if (mode == EngineMode.VERSION) { - if (sources.size() > 1) { - throw new Exception("Can only have one source when converting versions (found "+sources+")"); + if (sources.size() > 1) { + throw new Exception("Can only have one source when converting versions (found " + sources + ")"); } - if (targetVer == null) { + if (targetVer == null) { throw new Exception("Must provide a map when converting versions"); } if (output == null) { @@ -624,15 +369,15 @@ public class Validator { System.out.println(" ...success"); TextFile.bytesToFile(r, output); } catch (Exception e) { - System.out.println(" ...Failure: "+e.getMessage()); + System.out.println(" ...Failure: " + e.getMessage()); e.printStackTrace(); } } else if (mode == EngineMode.TRANSFORM) { - if (sources.size() > 1) - throw new Exception("Can only have one source when doing a transform (found "+sources+")"); - if (txServer == null) + if (sources.size() > 1) + throw new Exception("Can only have one source when doing a transform (found " + sources + ")"); + if (txServer == null) throw new Exception("Must provide a terminology server when doing a transform"); - if (map == null) + if (map == null) throw new Exception("Must provide a map when doing a transform"); try { validator.setMapLog(mapLog); @@ -647,7 +392,7 @@ public class Validator { s.close(); } } catch (Exception e) { - System.out.println(" ...Failure: "+e.getMessage()); + System.out.println(" ...Failure: " + e.getMessage()); e.printStackTrace(); } } else if (mode == EngineMode.NARRATIVE) { @@ -656,7 +401,7 @@ public class Validator { if (output != null) { validator.handleOutput(r, output, sv); } - } else if (mode == EngineMode.SNAPSHOT) { + } else if (mode == EngineMode.SNAPSHOT) { StructureDefinition r = validator.snapshot(sources.get(0), sv); System.out.println(" ...generated snapshot successfully"); if (output != null) { @@ -666,14 +411,14 @@ public class Validator { validator.convert(sources.get(0), output); System.out.println(" ...convert"); } else if (mode == EngineMode.FHIRPATH) { - System.out.println(" ...evaluating "+fhirpath); + System.out.println(" ...evaluating " + fhirpath); System.out.println(validator.evaluateFhirPath(sources.get(0), fhirpath)); } else { - if (definitions == null) + if (definitions == null) throw new Exception("Must provide a defn when doing validation"); for (String s : profiles) { 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); validator.loadProfile(locations.getOrDefault(s, s)); } } @@ -681,30 +426,30 @@ public class Validator { 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"); + throw new Exception("Output '" + output + "' must be a directory when scanning"); + System.out.println(" .. scan " + sources + " against loaded IGs"); Set 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 res = validator.validateScan(sources, urls); - validator.genScanOutput(output, res); - System.out.println("Done. output in "+Utilities.path(output, "scan.html")); - } else { + validator.genScanOutput(output, res); + System.out.println("Done. output in " + Utilities.path(output, "scan.html")); + } else { if (profiles.size() > 0) - System.out.println(" .. validate "+sources+" against "+profiles.toString()); + System.out.println(" .. validate " + sources + " against " + profiles.toString()); else - System.out.println(" .. validate "+sources); + System.out.println(" .. validate " + sources); validator.prepare(); // generate any missing snapshots Resource r = validator.validate(sources, profiles); int ec = 0; if (output == null) { if (r instanceof Bundle) - for (BundleEntryComponent e : ((Bundle)r).getEntry()) - ec = displayOO((OperationOutcome)e.getResource()) + ec; + for (BundleEntryComponent e : ((Bundle) r).getEntry()) + ec = displayOO((OperationOutcome) e.getResource()) + ec; else - ec = displayOO((OperationOutcome)r); + ec = displayOO((OperationOutcome) r); } else { FileOutputStream s = new FileOutputStream(output); x.compose(s, r); @@ -716,11 +461,29 @@ public class Validator { } } - private static String chooseName(String[] args, String name, CanonicalResource mr) { - String s = getParam(args, "-"+name); - if (Utilities.noString(s)) - s = mr.present(); - return s; + public static String resolveSnomedCTCode(String s) { + String snomedCT; + if ("intl".equalsIgnoreCase(s)) + snomedCT = "900000000000207008"; + else if ("us".equalsIgnoreCase(s)) + snomedCT = "731000124108"; + else if ("uk".equalsIgnoreCase(s)) + snomedCT = "999000041000000102"; + else if ("au".equalsIgnoreCase(s)) + snomedCT = "32506021000036107"; + else if ("ca".equalsIgnoreCase(s)) + snomedCT = "20611000087101"; + else if ("nl".equalsIgnoreCase(s)) + snomedCT = "11000146104"; + else if ("se".equalsIgnoreCase(s)) + snomedCT = "45991000052106"; + else if ("es".equalsIgnoreCase(s)) + snomedCT = "449081005"; + else if ("dk".equalsIgnoreCase(s)) + snomedCT = "554471000005108"; + else + throw new Error("Snomed edition '" + s + "' not known"); + return snomedCT; } private static String getGitBuild() { @@ -734,15 +497,15 @@ public class Validator { String file = ToolingExtensions.readStringExtension(oo, ToolingExtensions.EXT_OO_FILE); for (OperationOutcomeIssueComponent issue : oo.getIssue()) { - if (issue.getSeverity()==OperationOutcome.IssueSeverity.FATAL || issue.getSeverity()==OperationOutcome.IssueSeverity.ERROR) + if (issue.getSeverity() == OperationOutcome.IssueSeverity.FATAL || issue.getSeverity() == OperationOutcome.IssueSeverity.ERROR) error++; - else if (issue.getSeverity()==OperationOutcome.IssueSeverity.WARNING) + else if (issue.getSeverity() == OperationOutcome.IssueSeverity.WARNING) warn++; else info++; } - System.out.println((error==0?"Success...":"*FAILURE* ")+ "validating "+file+": "+" error:"+Integer.toString(error)+" warn:"+Integer.toString(warn)+" info:"+Integer.toString(info)); + System.out.println((error == 0 ? "Success..." : "*FAILURE* ") + "validating " + file + ": " + " error:" + Integer.toString(error) + " warn:" + Integer.toString(warn) + " info:" + Integer.toString(info)); for (OperationOutcomeIssueComponent issue : oo.getIssue()) { System.out.println(getIssueSummary(issue)); } @@ -755,38 +518,15 @@ public class Validator { if (issue.hasExpression()) { int line = ToolingExtensions.readIntegerExtension(issue, ToolingExtensions.EXT_ISSUE_LINE, -1); int col = ToolingExtensions.readIntegerExtension(issue, ToolingExtensions.EXT_ISSUE_COL, -1); - loc = issue.getExpression().get(0).asStringValue() + (line >= 0 && col >= 0 ? " (line "+Integer.toString(line)+", col"+Integer.toString(col)+")" : ""); + loc = issue.getExpression().get(0).asStringValue() + (line >= 0 && col >= 0 ? " (line " + Integer.toString(line) + ", col" + Integer.toString(col) + ")" : ""); } else if (issue.hasLocation()) { loc = issue.getLocation().get(0).asStringValue(); } else { int line = ToolingExtensions.readIntegerExtension(issue, ToolingExtensions.EXT_ISSUE_LINE, -1); int col = ToolingExtensions.readIntegerExtension(issue, ToolingExtensions.EXT_ISSUE_COL, -1); - loc = (line >= 0 && col >= 0 ? "line "+Integer.toString(line)+", col"+Integer.toString(col) : "??"); + loc = (line >= 0 && col >= 0 ? "line " + Integer.toString(line) + ", col" + Integer.toString(col) : "??"); } return " " + issue.getSeverity().getDisplay() + " @ " + loc + " : " + issue.getDetails().getText(); } - - private static boolean hasParam(String[] args, String param) { - for (String a : args) - if (a.equals(param)) - return true; - return false; - } - - private static String getParam(String[] args, String param) { - for (int i = 0; i < args.length - 1; i++) - if (args[i].equals(param)) - return args[i+1]; - return null; - } - - - private static boolean hasTransformParam(String[] args) { - for (String s : args) { - if (s.equals("-transform")) - return true; - } - return false; - } } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/CliContext.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/CliContext.java new file mode 100644 index 000000000..d09882b8b --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/CliContext.java @@ -0,0 +1,4 @@ +package org.hl7.fhir.validation.cliutils; + +public class CliContext { +} diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ComparisonUtils.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ComparisonUtils.java new file mode 100644 index 000000000..af39679c3 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ComparisonUtils.java @@ -0,0 +1,98 @@ +package org.hl7.fhir.validation.cliutils; + +import org.hl7.fhir.r5.conformance.CapabilityStatementUtilities; +import org.hl7.fhir.r5.conformance.ProfileComparer; +import org.hl7.fhir.r5.formats.IParser; +import org.hl7.fhir.r5.formats.JsonParser; +import org.hl7.fhir.r5.formats.XmlParser; +import org.hl7.fhir.r5.model.CanonicalResource; +import org.hl7.fhir.r5.model.CapabilityStatement; +import org.hl7.fhir.r5.model.Resource; +import org.hl7.fhir.r5.model.StructureDefinition; +import org.hl7.fhir.r5.utils.KeyGenerator; +import org.hl7.fhir.utilities.TextFile; +import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.utilities.validation.ValidationMessage; +import org.hl7.fhir.validation.ValidationEngine; + +import java.awt.*; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.UUID; + +public class ComparisonUtils { + + public static void doLeftRightComparison(String[] args, String dest, ValidationEngine validator) throws IOException { + // ok now set up the comparison + String left = ParamUtils.getParam(args, "-left"); + String right = ParamUtils.getParam(args, "-right"); + + Resource resLeft = validator.getContext().fetchResource(Resource.class, left); + Resource resRight = validator.getContext().fetchResource(Resource.class, right); + if (resLeft == null) { + System.out.println("Unable to locate left resource " +left); + } + if (resRight == null) { + System.out.println("Unable to locate right resource " +right); + } + + if (resLeft != null && resRight != null) { + if (resLeft instanceof StructureDefinition && resRight instanceof StructureDefinition) { + ComparisonUtils.compareStructureDefinitions(dest, validator, left, right, (StructureDefinition) resLeft, (StructureDefinition) resRight); + } else if (resLeft instanceof CapabilityStatement && resRight instanceof CapabilityStatement) { + ComparisonUtils.compareCapabilityStatements(args, dest, validator, left, right, (CanonicalResource) resLeft, (CanonicalResource) resRight); + } else + System.out.println("Unable to compare left resource " + left + " (" + resLeft.fhirType() + ") with right resource " + right + " (" + resRight.fhirType() + ")"); + } + } + + public static void compareCapabilityStatements(String[] args, String dest, ValidationEngine validator, String left, String right, CanonicalResource resLeft, CanonicalResource resRight) throws IOException { + String nameLeft = chooseName(args, "leftName", resLeft); + String nameRight = chooseName(args, "rightName", resRight); + System.out.println("Comparing CapabilityStatements " + left + " to " + right); + CapabilityStatementUtilities pc = new CapabilityStatementUtilities(validator.getContext(), dest, new KeyGenerator("http://fhir.org/temp/" + UUID.randomUUID().toString().toLowerCase())); + CapabilityStatement capL = (CapabilityStatement) resLeft; + CapabilityStatement capR = (CapabilityStatement) resRight; + CapabilityStatementUtilities.CapabilityStatementComparisonOutput output = pc.isCompatible(nameLeft, nameRight, capL, capR); + + String destTxt = Utilities.path(dest, "output.txt"); + System.out.println("Generating output to " + destTxt + "..."); + StringBuilder b = new StringBuilder(); + for (ValidationMessage msg : output.getMessages()) { + b.append(msg.summary()); + b.append("\r\n"); + } + TextFile.stringToFile(b.toString(), destTxt); + new XmlParser().setOutputStyle(IParser.OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(dest, "CapabilityStatement-union.xml")), output.getSuperset()); + new XmlParser().setOutputStyle(IParser.OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(dest, "CapabilityStatement-intersection.xml")), output.getSubset()); + new XmlParser().setOutputStyle(IParser.OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(dest, "OperationOutcome-issues.xml")), output.getOutcome()); + new JsonParser().setOutputStyle(IParser.OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(dest, "CapabilityStatement-union.json")), output.getSuperset()); + new JsonParser().setOutputStyle(IParser.OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(dest, "CapabilityStatement-intersection.json")), output.getSubset()); + new JsonParser().setOutputStyle(IParser.OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(dest, "OperationOutcome-issues.json")), output.getOutcome()); + + String destHtml = Utilities.path(dest, "index.html"); + File htmlFile = new File(destHtml); + Desktop.getDesktop().browse(htmlFile.toURI()); + System.out.println("Done"); + } + + public static void compareStructureDefinitions(String dest, ValidationEngine validator, String left, String right, StructureDefinition resLeft, StructureDefinition resRight) throws IOException { + System.out.println("Comparing StructureDefinitions " + left + " to " + right); + ProfileComparer pc = new ProfileComparer(validator.getContext(), dest); + StructureDefinition sdL = resLeft; + StructureDefinition sdR = resRight; + pc.compareProfiles(sdL, sdR); + System.out.println("Generating output to " + dest + "..."); + File htmlFile = new File(pc.generate()); + Desktop.getDesktop().browse(htmlFile.toURI()); + System.out.println("Done"); + } + + private static String chooseName(String[] args, String name, CanonicalResource mr) { + String s = ParamUtils.getParam(args, "-" + name); + if (Utilities.noString(s)) + s = mr.present(); + return s; + } +} diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/DisplayUtils.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/DisplayUtils.java new file mode 100644 index 000000000..f5a7f4c18 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/DisplayUtils.java @@ -0,0 +1,143 @@ +package org.hl7.fhir.validation.cliutils; + +import org.hl7.fhir.r5.model.Constants; +import org.hl7.fhir.utilities.VersionUtilities; +import org.hl7.fhir.utilities.cache.PackageCacheManager; +import org.hl7.fhir.utilities.cache.ToolsVersion; + +import java.io.IOException; + +public class DisplayUtils { + + public static void printCliArgumentsAndInfo(String[] args) throws IOException { + System.out.print("Arguments:"); + for (String s : args) { + System.out.print(s.contains(" ") ? " \"" + s + "\"" : " " + s); + } + System.out.println(); + System.out.println("Directories: Current = " + System.getProperty("user.dir") + ", Package Cache = " + new PackageCacheManager(true, ToolsVersion.TOOLS_VERSION).getFolder()); + } + + public static void displayHelpDetails() { + System.out.println(""); + System.out.println("The FHIR validation tool validates a FHIR resource or bundle."); + System.out.println("The validation tool compares a resource against the base definitions and any"); + System.out.println("profiles declared in the resource (Resource.meta.profile) or specified on the "); + System.out.println("command line"); + System.out.println(""); + System.out.println("The FHIR validation tool validates a FHIR resource or bundle."); + 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(""); + 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"); + } + +} diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ParamUtils.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ParamUtils.java new file mode 100644 index 000000000..23bbc55fc --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ParamUtils.java @@ -0,0 +1,33 @@ +package org.hl7.fhir.validation.cliutils; + +public class ParamUtils { + + /** TODO proper error checking, streams + * Checks the list of passed in params to see if it contains the passed in param. + * + * @param args Array of params to search. + * @param param {@link String} param to search for. + * @return {@link Boolean#TRUE} if the list contains the given param. + */ + public static boolean hasParam(String[] args, String param) { + for (String a : args) + if (a.equals(param)) + return true; + return false; + } + + /** TODO proper error checking, streams + * Fetches the vlaue for the passed in param from the provided list of params. + * + * @param args Array of params to search. + * @param param {@link String} param keyword to search for. + * @return {@link String} value for the provided param. + */ + public static String getParam(String[] args, String param) { + for (int i = 0; i < args.length - 1; i++) + if (args[i].equals(param)) + return args[i + 1]; + return null; + } + +} diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Utils.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Utils.java new file mode 100644 index 000000000..4ff8169fe --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Utils.java @@ -0,0 +1,129 @@ +package org.hl7.fhir.validation.cliutils; + +import org.hl7.fhir.r5.context.SimpleWorkerContext; +import org.hl7.fhir.r5.model.Constants; +import org.hl7.fhir.r5.model.FhirPublication; +import org.hl7.fhir.r5.model.Resource; +import org.hl7.fhir.utilities.VersionUtilities; +import org.hl7.fhir.validation.ValidationEngine; + +import java.io.File; + +public class Utils { + + + public static String getVersion(String[] args) { + String v = ParamUtils.getParam(args, "-version"); + if (v == null) { + v = "current"; + for (int i = 0; i < args.length; i++) { + if ("-ig".equals(args[i])) { + if (i + 1 == args.length) + throw new Error("Specified -ig without indicating ig file"); + else { + String n = args[i + 1]; + v = Utils.getVersionFromIGName(v, n); + } + } + } + } else if ("1.0".equals(v)) { + v = "1.0"; + } else if ("1.4".equals(v)) { + v = "1.4"; + } else if ("3.0".equals(v)) { + v = "3.0"; + } else if ("4.0".equals(v)) { + v = "4.0"; + } else if (v.startsWith(Constants.VERSION)) { + v = "current"; + } + return v; + } + + /** + * Evaluates the current implementation guide file name and sets the current version accordingly. + * + * If igFileName is not one of the known patterns, will return whatever value is passed in as default. + * + * @param defaultValue Version to return if no associated version can be determined from passed in igFileName + * @param igFileName Name of the implementation guide + * @return + */ + public static String getVersionFromIGName(String defaultValue, String igFileName) { + if (igFileName.startsWith("hl7.fhir.core#")) { + defaultValue = VersionUtilities.getCurrentPackageVersion(igFileName.substring(14)); + } else if (igFileName.startsWith("hl7.fhir.r2.core#") || igFileName.equals("hl7.fhir.r2.core")) { + defaultValue = "1.0"; + } else if (igFileName.startsWith("hl7.fhir.r2b.core#") || igFileName.equals("hl7.fhir.r2b.core")) { + defaultValue = "1.4"; + } else if (igFileName.startsWith("hl7.fhir.r3.core#") || igFileName.equals("hl7.fhir.r3.core")) { + defaultValue = "3.0"; + } else if (igFileName.startsWith("hl7.fhir.r4.core#") || igFileName.equals("hl7.fhir.r4.core")) { + defaultValue = "4.0"; + } else if (igFileName.startsWith("hl7.fhir.r5.core#") || igFileName.equals("hl7.fhir.r5.core")) { + defaultValue = "current"; + } + return defaultValue; + } + + + /** + * Triggers the validation engine tests to run. + */ + public static void runValidationEngineTests() { + try { + Class clazz = Class.forName("org.hl7.fhir.validation.r5.tests.ValidationEngineTests"); + clazz.getMethod("execute").invoke(clazz); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static String getTerminologyServerLog(String[] args) { + String txLog = null; + if (ParamUtils.hasParam(args, "-txLog")) { + txLog = ParamUtils.getParam(args, "-txLog"); + new File(txLog).delete(); + } + return txLog; + } + + public static ValidationEngine getValidationEngine(String[] args, String txLog) throws Exception { + String v = Utils.getVersion(args); + String definitions = VersionUtilities.packageForVersion(v) + "#" + v; + System.out.println("Loading (v = " + v + ", tx server http://tx.fhir.org)"); + return new ValidationEngine(definitions, "http://tx.fhir.org", txLog, FhirPublication.fromCode(v), v); + } + + public static void checkIGFileReferences(String[] args) { + for (int i = 0; i < args.length; i++) { + if ("-ig".equals(args[i])) { + if (i + 1 == args.length) + throw new Error("Specified -ig without indicating ig file"); + else { + String s = args[++i]; + if (!s.startsWith("hl7.fhir.core-")) { + System.out.println("Load Package: " + s); + } + } + } + } + } + + private static Resource loadResource(String[] args, String param, SimpleWorkerContext context) { + String resString = ParamUtils.getParam(args, param); + Resource resource = context.fetchResource(Resource.class, resString); + if (resource == null) { + System.out.println("Unable to locate resource for " + param + ", " + resString); + } + return resource; + } + + public static Resource getRightResource(String[] args, SimpleWorkerContext context) { + return loadResource(args, "-right", context); + } + + public static Resource getLeftResource(String[] args, SimpleWorkerContext context) { + return loadResource(args, "-left", context); + } +} diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationEngineTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationEngineTests.java index 4aecd05ea..1b1694b53 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationEngineTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationEngineTests.java @@ -176,24 +176,6 @@ public class ValidationEngineTests { System.out.println(" .. done: "+Integer.toString(e)+" errors, "+Integer.toString(w)+" warnings, "+Integer.toString(h)+" information messages"); } -// @Test -// public void testTransform() throws Exception { -// if (!TestUtilities.silent) -// System.out.println("Transform CCDA"); -// if (!TestUtilities.silent) -// System.out.println(" .. load FHIR from " +Utilities.path(TestUtilities.home(), "publish")); -// ValidationEngine ve = new ValidationEngine(Utilities.path(TestUtilities.home(), "publish"), DEF_TX, null, FhirVersion.R4); -// if (!TestUtilities.silent) -// System.out.println(" .. load CCDA from " +Utilities.path(TestUtilities.home(), "guides\\ccda2\\mapping\\logical")); -// ve.loadIg(Utilities.path(TestUtilities.home(), "guides\\ccda2\\mapping\\logical")); -// if (!TestUtilities.silent) -// System.out.println(" .. load Maps from " +Utilities.path(TestUtilities.home(), "guides\\ccda2\\mapping\\map")); -// ve.loadIg(Utilities.path(TestUtilities.home(), "guides\\ccda2\\mapping\\map")); -// Resource r = ve.transform(Utilities.path(TestUtilities.home(), "guides\\ccda2\\mapping\\example\\ccd.xml"), "http://hl7.org/fhir/StructureMap/cda"); -// if (!TestUtilities.silent) -// System.out.println(" .. done"); -// } - private int errors(OperationOutcome op) { int i = 0; for (OperationOutcomeIssueComponent vm : op.getIssue()) { @@ -228,7 +210,6 @@ public class ValidationEngineTests { self.test102(); self.test140(); self.test301USCore(); -// self.testTransform(); System.out.println("Finished"); } From 6e9b760b757bc36a5716e9166bc3b81c5a481830 Mon Sep 17 00:00:00 2001 From: markiantorno Date: Thu, 2 Apr 2020 22:46:49 -0400 Subject: [PATCH 2/4] wip --- .../org/hl7/fhir/validation/Validator.java | 50 ++---------- .../fhir/validation/cliutils/CliContext.java | 29 +++++++ .../fhir/validation/cliutils/ParamArg.java | 81 +++++++++++++++++++ .../fhir/validation/cliutils/ParamUtils.java | 11 ++- .../validation/cliutils/SnomedVersion.java | 38 +++++++++ .../hl7/fhir/validation/cliutils/Utils.java | 5 +- 6 files changed, 161 insertions(+), 53 deletions(-) create mode 100644 org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ParamArg.java create mode 100644 org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/SnomedVersion.java diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Validator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Validator.java index edab6776a..af381bcd6 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Validator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Validator.java @@ -88,10 +88,7 @@ import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.validation.ValidationMessage; -import org.hl7.fhir.validation.cliutils.ComparisonUtils; -import org.hl7.fhir.validation.cliutils.DisplayUtils; -import org.hl7.fhir.validation.cliutils.ParamUtils; -import org.hl7.fhir.validation.cliutils.Utils; +import org.hl7.fhir.validation.cliutils.*; /** * A executable class that will validate one or more FHIR resources against @@ -224,7 +221,7 @@ public class Validator { doDebug = true; } else if (args[i].equals("-sct")) { String s = args[++i]; - snomedCT = resolveSnomedCTCode(s); + snomedCT = SnomedVersion.resolveSnomedCTCode(s); } else if (args[i].equals("-recurse")) { recursive = true; } else if (args[i].equals("-locale")) { @@ -278,22 +275,10 @@ public class Validator { throw new Error("Specified " + args[i] + " without indicating ig file"); else { String s = args[++i]; - if (s.equals("hl7.fhir.core")) { - sv = "current"; - } else if (s.startsWith("hl7.fhir.core#")) { - sv = VersionUtilities.getCurrentPackageVersion(s.substring(14)); - } else if (s.startsWith("hl7.fhir.r2.core#") || s.equals("hl7.fhir.r2.core")) { - sv = "1.0"; - } else if (s.startsWith("hl7.fhir.r2b.core#") || s.equals("hl7.fhir.r2b.core")) { - sv = "1.4"; - } else if (s.startsWith("hl7.fhir.r3.core#") || s.equals("hl7.fhir.r3.core")) { - sv = "3.0"; - } else if (s.startsWith("hl7.fhir.r4.core#") || s.equals("hl7.fhir.r4.core")) { - sv = "4.0"; - } else if (s.startsWith("hl7.fhir.r5.core#") || s.equals("hl7.fhir.r5.core")) { - sv = "current"; - } else + sv = Utils.getVersionFromIGName(null, s); + if (sv == null) { igs.add(s); + } } } else if (args[i].equals("-map")) { if (map == null) { @@ -461,31 +446,6 @@ public class Validator { } } - public static String resolveSnomedCTCode(String s) { - String snomedCT; - if ("intl".equalsIgnoreCase(s)) - snomedCT = "900000000000207008"; - else if ("us".equalsIgnoreCase(s)) - snomedCT = "731000124108"; - else if ("uk".equalsIgnoreCase(s)) - snomedCT = "999000041000000102"; - else if ("au".equalsIgnoreCase(s)) - snomedCT = "32506021000036107"; - else if ("ca".equalsIgnoreCase(s)) - snomedCT = "20611000087101"; - else if ("nl".equalsIgnoreCase(s)) - snomedCT = "11000146104"; - else if ("se".equalsIgnoreCase(s)) - snomedCT = "45991000052106"; - else if ("es".equalsIgnoreCase(s)) - snomedCT = "449081005"; - else if ("dk".equalsIgnoreCase(s)) - snomedCT = "554471000005108"; - else - throw new Error("Snomed edition '" + s + "' not known"); - return snomedCT; - } - private static String getGitBuild() { return "??"; } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/CliContext.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/CliContext.java index d09882b8b..63661c8fe 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/CliContext.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/CliContext.java @@ -1,4 +1,33 @@ package org.hl7.fhir.validation.cliutils; +import org.hl7.fhir.validation.Validator; + +import java.util.*; + public class CliContext { + + private String map = null; + private List igs = new ArrayList(); + private List questionnaires = new ArrayList(); + private String txServer = "http://tx.fhir.org"; + private boolean doNative = false; + private boolean anyExtensionsAllowed = true; + private boolean hintAboutNonMustSupport = false; + private boolean recursive = false; + private Locale locale = null; + private List profiles = new ArrayList(); + private Validator.EngineMode mode = Validator.EngineMode.VALIDATION; + private String output = null; + private Boolean canDoNative = null; + private List sources = new ArrayList(); + private Map locations = new HashMap(); + private String sv = "current"; + private String txLog = null; + private String mapLog = null; + private String lang = null; + private String fhirpath = null; + private String snomedCT = "900000000000207008"; + private String targetVer = null; + private boolean doDebug = false; + private boolean assumeValidRestReferences = false; } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ParamArg.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ParamArg.java new file mode 100644 index 000000000..b27ac9050 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ParamArg.java @@ -0,0 +1,81 @@ +package org.hl7.fhir.validation.cliutils; + +public enum ParamArg { + VERSION("-version"), + OUTPUT("-output"), + PROXY("-proxy"), + PROFILE("-profile"), + QUESTIONNAIRE("-questionnaire"), + NATIVE("-native"), + ASSUME_VALID_REST_REF("-assumeValidRestReferences"), + DEBUG("-debug"), + SCT("-sct"), + RECURSE("-recurse"), + LOCALE("-locale"), + STRICT_EXTENSIONS("-strictExtensions"), + HINT_ABOUT_NON_MUST_SUPPORT("-hintAboutNonMustSupport"), + TO_VERSION("-to-version"), + DO_NATIVE("-do-native"), + NO_NATIVE("-no-native"), + TRANSFORM("-transform"), + NARRATIVE("-narrative"), + SNAPSHOT("-snapshot"), + SCAN("-scan"), + TERMINOLOGY("-tx"), + TERMINOLOGY_LOG("-txLog"); + + private final String code; + + ParamArg(String code) { + this.code = code; + } + +} + + +// } else if (args[i].equals("-log")) { +// if (i + 1 == args.length) +// throw new Error("Specified -log without indicating file"); +// else +// mapLog = args[++i]; +// } else if (args[i].equals("-language")) { +// if (i + 1 == args.length) +// throw new Error("Specified -language without indicating language"); +// else +// lang = args[++i]; +// } else if (args[i].equals("-ig") || args[i].equals("-defn")) { +// if (i + 1 == args.length) +// throw new Error("Specified " + args[i] + " without indicating ig file"); +// else { +// String s = args[++i]; +// sv = Utils.getVersionFromIGName(null, s); +// if (sv == null) { +// igs.add(s); +// } +// } +// } else if (args[i].equals("-map")) { +// if (map == null) { +// if (i + 1 == args.length) +// throw new Error("Specified -map without indicating map file"); +// else +// map = args[++i]; +// } else { +// throw new Exception("Can only nominate a single -map parameter"); +// } +// } else if (args[i].startsWith("-x")) { +// i++; +// } else if (args[i].equals("-convert")) { +// mode = EngineMode.CONVERT; +// } else if (args[i].equals("-fhirpath")) { +// mode = EngineMode.FHIRPATH; +// if (fhirpath == null) +// if (i + 1 == args.length) +// throw new Error("Specified -fhirpath without indicating a FHIRPath expression"); +// else +// fhirpath = args[++i]; +// else +// throw new Exception("Can only nominate a single -fhirpath parameter"); +// } else { +// sources.add(args[i]); +// } +// } \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ParamUtils.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ParamUtils.java index 23bbc55fc..32913524d 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ParamUtils.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ParamUtils.java @@ -1,8 +1,10 @@ package org.hl7.fhir.validation.cliutils; +import java.util.Arrays; + public class ParamUtils { - /** TODO proper error checking, streams + /** * Checks the list of passed in params to see if it contains the passed in param. * * @param args Array of params to search. @@ -10,13 +12,10 @@ public class ParamUtils { * @return {@link Boolean#TRUE} if the list contains the given param. */ public static boolean hasParam(String[] args, String param) { - for (String a : args) - if (a.equals(param)) - return true; - return false; + return Arrays.asList(args).contains(param); } - /** TODO proper error checking, streams + /** * Fetches the vlaue for the passed in param from the provided list of params. * * @param args Array of params to search. diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/SnomedVersion.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/SnomedVersion.java new file mode 100644 index 000000000..ea26fbfa6 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/SnomedVersion.java @@ -0,0 +1,38 @@ +package org.hl7.fhir.validation.cliutils; + +import java.util.Arrays; +import java.util.Optional; + +public enum SnomedVersion { + INTL("intl", "900000000000207008"), + US("us", "731000124108"), + UK("uk", "999000041000000102"), + AU("au", "32506021000036107"), + CA("ca", "20611000087101"), + NL("nl", "11000146104"), + SE("se", "45991000052106"), + ES("es", "449081005"), + DK("dk", "554471000005108"); + + private static final String DEFAULT_CODE = "900000000000207008"; + + private final String lang; + private final String code; + + SnomedVersion(String lang, String code) { + this.lang = lang; + this.code = code; + } + + public static String resolveSnomedCTCode(String s) { + String foundCode; + Optional opt = Arrays.stream(values()) + .filter(v -> v.lang.equals(s)) + .findFirst(); + if (opt.isPresent()) { + return opt.get().code; + } else { + throw new Error("Snomed edition '" + s + "' not known"); + } + } +} diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Utils.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Utils.java index 4ff8169fe..37cd63218 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Utils.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Utils.java @@ -50,7 +50,9 @@ public class Utils { * @return */ public static String getVersionFromIGName(String defaultValue, String igFileName) { - if (igFileName.startsWith("hl7.fhir.core#")) { + if (igFileName.equals("hl7.fhir.core")) { + defaultValue = "current"; + } else if (igFileName.startsWith("hl7.fhir.core#")) { defaultValue = VersionUtilities.getCurrentPackageVersion(igFileName.substring(14)); } else if (igFileName.startsWith("hl7.fhir.r2.core#") || igFileName.equals("hl7.fhir.r2.core")) { defaultValue = "1.0"; @@ -66,7 +68,6 @@ public class Utils { return defaultValue; } - /** * Triggers the validation engine tests to run. */ From 0e45efb7660e19366a4a759dc144bb62fb5509c3 Mon Sep 17 00:00:00 2001 From: markiantorno Date: Fri, 3 Apr 2020 14:04:03 -0400 Subject: [PATCH 3/4] Cleaning up validator --- .../org/hl7/fhir/validation/Validator.java | 402 ++---------------- .../fhir/validation/cliutils/CliContext.java | 258 ++++++++++- .../cliutils/{Utils.java => Common.java} | 36 +- .../{ComparisonUtils.java => Comparison.java} | 18 +- .../{DisplayUtils.java => Display.java} | 10 +- .../fhir/validation/cliutils/ParamArg.java | 81 ---- .../fhir/validation/cliutils/ParamUtils.java | 32 -- .../hl7/fhir/validation/cliutils/Params.java | 210 +++++++++ .../validation/cliutils/SnomedVersion.java | 8 + .../validation/cliutils/ValidationUtils.java | 198 +++++++++ 10 files changed, 730 insertions(+), 523 deletions(-) rename org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/{Utils.java => Common.java} (76%) rename org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/{ComparisonUtils.java => Comparison.java} (87%) rename org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/{DisplayUtils.java => Display.java} (95%) delete mode 100644 org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ParamArg.java delete mode 100644 org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ParamUtils.java create mode 100644 org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Params.java create mode 100644 org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ValidationUtils.java diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Validator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Validator.java index af381bcd6..bc4241fde 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Validator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Validator.java @@ -48,46 +48,12 @@ POSSIBILITY OF SUCH DAMAGE. */ -import java.awt.Desktop; import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import org.hl7.fhir.r5.conformance.CapabilityStatementUtilities; -import org.hl7.fhir.r5.conformance.CapabilityStatementUtilities.CapabilityStatementComparisonOutput; -import org.hl7.fhir.r5.conformance.ProfileComparer; -import org.hl7.fhir.r5.context.SimpleWorkerContext; -import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat; -import org.hl7.fhir.r5.formats.IParser; -import org.hl7.fhir.r5.formats.IParser.OutputStyle; -import org.hl7.fhir.r5.formats.XmlParser; -import org.hl7.fhir.r5.formats.JsonParser; -import org.hl7.fhir.r5.model.Bundle; -import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent; -import org.hl7.fhir.r5.model.CapabilityStatement; -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.CanonicalResource; -import org.hl7.fhir.r5.model.OperationOutcome; -import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent; -import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.StructureDefinition; -import org.hl7.fhir.r5.utils.KeyGenerator; -import org.hl7.fhir.r5.utils.ToolingExtensions; -import org.hl7.fhir.validation.ValidationEngine.ScanOutputItem; -import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; -import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.validation.cliutils.*; /** @@ -128,365 +94,67 @@ public class Validator { public static void main(String[] args) throws Exception { System.out.println("FHIR Validation tool " + VersionUtil.getVersionString()); System.out.println("Detected Java version: " + 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"); - String proxy = getNamedParam(args, "-proxy"); + String proxy = getNamedParam(args, Params.PROXY); if (!Utilities.noString(proxy)) { String[] p = proxy.split("\\:"); System.setProperty("http.proxyHost", p[0]); System.setProperty("http.proxyPort", p[1]); } - if (ParamUtils.hasParam(args, "-tests")) { - Utils.runValidationEngineTests(); - } else if (args.length == 0 || ParamUtils.hasParam(args, "help") || ParamUtils.hasParam(args, "?") || ParamUtils.hasParam(args, "-?") || ParamUtils.hasParam(args, "/?")) { - DisplayUtils.displayHelpDetails(); - } else if (ParamUtils.hasParam(args, "-compare")) { - DisplayUtils.printCliArgumentsAndInfo(args); - String dest = ParamUtils.getParam(args, "-dest"); + if (Params.hasParam(args, Params.TEST)) { + Common.runValidationEngineTests(); + } else if (args.length == 0 || Params.hasParam(args, Params.HELP) || Params.hasParam(args, "?") || Params.hasParam(args, "-?") || Params.hasParam(args, "/?")) { + Display.displayHelpDetails(); + } else if (Params.hasParam(args, Params.COMPARE)) { + Display.printCliArgumentsAndInfo(args); + String dest = Params.getParam(args, Params.DESTINATION); 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 - String txLog = Utils.getTerminologyServerLog(args); - ValidationEngine validator = Utils.getValidationEngine(args, txLog); - Utils.checkIGFileReferences(args); - ComparisonUtils.doLeftRightComparison(args, dest, validator); + String txLog = Common.getTerminologyServerLog(args); + ValidationEngine validator = Common.getValidationEngine(args, txLog); + Common.checkIGFileReferences(args); + Comparison.doLeftRightComparison(args, dest, validator); } } else { - DisplayUtils.printCliArgumentsAndInfo(args); - - String map = null; - List igs = new ArrayList(); - List questionnaires = new ArrayList(); - String txServer = "http://tx.fhir.org"; - boolean doNative = false; - boolean anyExtensionsAllowed = true; - boolean hintAboutNonMustSupport = false; - boolean recursive = false; - Locale locale = null; - List profiles = new ArrayList(); - EngineMode mode = EngineMode.VALIDATION; - String output = null; - Boolean canDoNative = null; - List sources = new ArrayList(); - Map locations = new HashMap(); - String sv = "current"; - String txLog = null; - String mapLog = null; - String lang = null; - String fhirpath = null; - String snomedCT = "900000000000207008"; - String targetVer = null; - boolean doDebug = false; - boolean assumeValidRestReferences = false; - - // load the parameters - so order doesn't matter - for (int i = 0; i < args.length; i++) { - if (args[i].equals("-version")) { - sv = args[++i]; - sv = VersionUtilities.getCurrentPackageVersion(sv); - } else if (args[i].equals("-output")) { - if (i + 1 == args.length) - throw new Error("Specified -output without indicating output file"); - else - output = args[++i]; - } else if (args[i].equals("-proxy")) { - i++; // ignore next parameter - } else if (args[i].equals("-profile")) { - String p = null; - if (i + 1 == args.length) - throw new Error("Specified -profile without indicating profile source"); - else { - p = args[++i]; - profiles.add(p); - } - if (p != null && i + 1 < args.length && args[i + 1].equals("@")) { - i++; - if (i + 1 == args.length) - throw new Error("Specified -profile with @ without indicating profile location"); - else - locations.put(p, args[++i]); - } - } else if (args[i].equals("-questionnaire")) { - if (i + 1 == args.length) - throw new Error("Specified -questionnaire without indicating questionnaire file"); - else - questionnaires.add(args[++i]); - } else if (args[i].equals("-native")) { - doNative = true; - } else if (args[i].equals("-assumeValidRestReferences")) { - assumeValidRestReferences = true; - } else if (args[i].equals("-debug")) { - doDebug = true; - } else if (args[i].equals("-sct")) { - String s = args[++i]; - snomedCT = SnomedVersion.resolveSnomedCTCode(s); - } else if (args[i].equals("-recurse")) { - recursive = true; - } else if (args[i].equals("-locale")) { - if (i + 1 == args.length) { - throw new Error("Specified -locale without indicating locale"); - } else { - locale = new Locale(args[++i]); - } - } else if (args[i].equals("-strictExtensions")) { - anyExtensionsAllowed = false; - } else if (args[i].equals("-hintAboutNonMustSupport")) { - hintAboutNonMustSupport = true; - } else if (args[i].equals("-to-version")) { - targetVer = args[++i]; - mode = EngineMode.VERSION; - } else if (args[i].equals("-do-native")) { - canDoNative = true; - } else if (args[i].equals("-no-native")) { - canDoNative = false; - } else if (args[i].equals("-transform")) { - map = args[++i]; - mode = EngineMode.TRANSFORM; - } else if (args[i].equals("-narrative")) { - mode = EngineMode.NARRATIVE; - } else if (args[i].equals("-snapshot")) { - mode = EngineMode.SNAPSHOT; - } else if (args[i].equals("-scan")) { - mode = EngineMode.SCAN; - } else if (args[i].equals("-tx")) { - if (i + 1 == args.length) - throw new Error("Specified -tx without indicating terminology server"); - else - txServer = "n/a".equals(args[++i]) ? null : args[i]; - } else if (args[i].equals("-txLog")) { - if (i + 1 == args.length) - throw new Error("Specified -txLog without indicating file"); - else - txLog = args[++i]; - } else if (args[i].equals("-log")) { - if (i + 1 == args.length) - throw new Error("Specified -log without indicating file"); - else - mapLog = args[++i]; - } else if (args[i].equals("-language")) { - if (i + 1 == args.length) - throw new Error("Specified -language without indicating language"); - else - lang = args[++i]; - } else if (args[i].equals("-ig") || args[i].equals("-defn")) { - if (i + 1 == args.length) - throw new Error("Specified " + args[i] + " without indicating ig file"); - else { - String s = args[++i]; - sv = Utils.getVersionFromIGName(null, s); - if (sv == null) { - igs.add(s); - } - } - } else if (args[i].equals("-map")) { - if (map == null) { - if (i + 1 == args.length) - throw new Error("Specified -map without indicating map file"); - else - map = args[++i]; - } else { - throw new Exception("Can only nominate a single -map parameter"); - } - } else if (args[i].startsWith("-x")) { - i++; - } else if (args[i].equals("-convert")) { - mode = EngineMode.CONVERT; - } else if (args[i].equals("-fhirpath")) { - mode = EngineMode.FHIRPATH; - if (fhirpath == null) - if (i + 1 == args.length) - throw new Error("Specified -fhirpath without indicating a FHIRPath expression"); - else - fhirpath = args[++i]; - else - throw new Exception("Can only nominate a single -fhirpath parameter"); - } else { - sources.add(args[i]); - } - } - if (sources.isEmpty()) - throw new Exception("Must provide at least one source file"); + Display.printCliArgumentsAndInfo(args); + CliContext cliContext = Params.loadCliContext(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 - String definitions = VersionUtilities.packageForVersion(sv) + "#" + VersionUtilities.getCurrentVersion(sv); - System.out.println(" .. FHIR Version " + sv + ", definitions from " + definitions); - System.out.println(" .. connect to tx server @ " + txServer); - ValidationEngine validator = new ValidationEngine(definitions, txServer, txLog, FhirPublication.fromCode(sv), sv); - validator.setDebug(doDebug); - System.out.println(" (v" + validator.getContext().getVersion() + ")"); - for (String src : igs) { - System.out.println("+ .. load IG from " + src); - validator.loadIg(src, recursive); - } - validator.setQuestionnaires(questionnaires); - validator.setNative(doNative); - validator.setHintAboutNonMustSupport(hintAboutNonMustSupport); - validator.setAnyExtensionsAllowed(anyExtensionsAllowed); - validator.setLanguage(lang); - validator.setLocale(locale); - validator.setSnomedExtension(snomedCT); - validator.setAssumeValidRestReferences(assumeValidRestReferences); + String definitions = VersionUtilities.packageForVersion(cliContext.getSv()) + "#" + VersionUtilities.getCurrentVersion(cliContext.getSv()); + ValidationEngine validator = ValidationUtils.getValidator(cliContext, definitions); - IParser x; - if (output != null && output.endsWith(".json")) - x = new JsonParser(); - else - x = new XmlParser(); - x.setOutputStyle(OutputStyle.PRETTY); - - if (mode == EngineMode.VERSION) { - if (sources.size() > 1) { - throw new Exception("Can only have one source when converting versions (found " + sources + ")"); - } - if (targetVer == null) { - throw new Exception("Must provide a map when converting versions"); - } - if (output == null) { - throw new Exception("Must nominate an output when converting versions"); - } - try { - if (mapLog != null) { - validator.setMapLog(mapLog); - } - byte[] r = validator.transformVersion(sources.get(0), targetVer, output.endsWith(".json") ? FhirFormat.JSON : FhirFormat.XML, canDoNative); - System.out.println(" ...success"); - TextFile.bytesToFile(r, output); - } catch (Exception e) { - System.out.println(" ...Failure: " + e.getMessage()); - e.printStackTrace(); - } - } else if (mode == EngineMode.TRANSFORM) { - if (sources.size() > 1) - throw new Exception("Can only have one source when doing a transform (found " + sources + ")"); - if (txServer == null) - throw new Exception("Must provide a terminology server when doing a transform"); - if (map == null) - throw new Exception("Must provide a map when doing a transform"); - try { - validator.setMapLog(mapLog); - org.hl7.fhir.r5.elementmodel.Element r = validator.transform(sources.get(0), map); - System.out.println(" ...success"); - if (output != null) { - FileOutputStream s = new FileOutputStream(output); - if (output != null && output.endsWith(".json")) - new org.hl7.fhir.r5.elementmodel.JsonParser(validator.getContext()).compose(r, s, OutputStyle.PRETTY, null); - else - new org.hl7.fhir.r5.elementmodel.XmlParser(validator.getContext()).compose(r, s, OutputStyle.PRETTY, null); - s.close(); - } - } catch (Exception e) { - System.out.println(" ...Failure: " + e.getMessage()); - e.printStackTrace(); - } - } else if (mode == EngineMode.NARRATIVE) { - DomainResource r = validator.generate(sources.get(0), sv); - System.out.println(" ...generated narrative successfully"); - if (output != null) { - validator.handleOutput(r, output, sv); - } - } else if (mode == EngineMode.SNAPSHOT) { - StructureDefinition r = validator.snapshot(sources.get(0), sv); - System.out.println(" ...generated snapshot successfully"); - if (output != null) { - validator.handleOutput(r, output, sv); - } - } else if (mode == EngineMode.CONVERT) { - validator.convert(sources.get(0), output); - System.out.println(" ...convert"); - } else if (mode == EngineMode.FHIRPATH) { - System.out.println(" ...evaluating " + fhirpath); - System.out.println(validator.evaluateFhirPath(sources.get(0), fhirpath)); + if (cliContext.getMode() == EngineMode.VERSION) { + ValidationUtils.transformVersion(cliContext, validator); + } else if (cliContext.getMode() == EngineMode.TRANSFORM) { + ValidationUtils.transform(cliContext, validator); + } else if (cliContext.getMode() == EngineMode.NARRATIVE) { + ValidationUtils.generateNarrative(cliContext, validator); + } else if (cliContext.getMode() == EngineMode.SNAPSHOT) { + ValidationUtils.generateSnapshot(cliContext, validator); + } else if (cliContext.getMode() == EngineMode.CONVERT) { + ValidationUtils.convertSources(cliContext, validator); + } else if (cliContext.getMode() == EngineMode.FHIRPATH) { + ValidationUtils.evaluateFhirpath(cliContext, validator); } else { - if (definitions == null) + if (definitions == null) { throw new Exception("Must provide a defn when doing validation"); - for (String s : profiles) { + } + for (String s : cliContext.getProfiles()) { if (!validator.getContext().hasResource(StructureDefinition.class, s) && !validator.getContext().hasResource(ImplementationGuide.class, s)) { System.out.println("Fetch Profile from " + s); - validator.loadProfile(locations.getOrDefault(s, s)); + validator.loadProfile(cliContext.getLocations().getOrDefault(s, s)); } } - if (mode == EngineMode.SCAN) { - 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 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 res = validator.validateScan(sources, urls); - validator.genScanOutput(output, res); - System.out.println("Done. output in " + Utilities.path(output, "scan.html")); + if (cliContext.getMode() == EngineMode.SCAN) { + ValidationUtils.validateScan(cliContext, validator); } else { - if (profiles.size() > 0) - System.out.println(" .. validate " + sources + " against " + profiles.toString()); - else - System.out.println(" .. validate " + sources); - validator.prepare(); // generate any missing snapshots - Resource r = validator.validate(sources, profiles); - int ec = 0; - if (output == null) { - if (r instanceof Bundle) - for (BundleEntryComponent e : ((Bundle) r).getEntry()) - ec = displayOO((OperationOutcome) e.getResource()) + ec; - else - ec = displayOO((OperationOutcome) r); - } else { - FileOutputStream s = new FileOutputStream(output); - x.compose(s, r); - s.close(); - } - System.exit(ec > 0 ? 1 : 0); + ValidationUtils.validateSources(cliContext, validator); } } } } - - private static String getGitBuild() { - return "??"; - } - - private static int displayOO(OperationOutcome oo) { - int error = 0; - int warn = 0; - int info = 0; - String file = ToolingExtensions.readStringExtension(oo, ToolingExtensions.EXT_OO_FILE); - - for (OperationOutcomeIssueComponent issue : oo.getIssue()) { - if (issue.getSeverity() == OperationOutcome.IssueSeverity.FATAL || issue.getSeverity() == OperationOutcome.IssueSeverity.ERROR) - error++; - else if (issue.getSeverity() == OperationOutcome.IssueSeverity.WARNING) - warn++; - else - info++; - } - - System.out.println((error == 0 ? "Success..." : "*FAILURE* ") + "validating " + file + ": " + " error:" + Integer.toString(error) + " warn:" + Integer.toString(warn) + " info:" + Integer.toString(info)); - for (OperationOutcomeIssueComponent issue : oo.getIssue()) { - System.out.println(getIssueSummary(issue)); - } - System.out.println(); - return error; - } - - private static String getIssueSummary(OperationOutcomeIssueComponent issue) { - String loc = null; - if (issue.hasExpression()) { - int line = ToolingExtensions.readIntegerExtension(issue, ToolingExtensions.EXT_ISSUE_LINE, -1); - int col = ToolingExtensions.readIntegerExtension(issue, ToolingExtensions.EXT_ISSUE_COL, -1); - loc = issue.getExpression().get(0).asStringValue() + (line >= 0 && col >= 0 ? " (line " + Integer.toString(line) + ", col" + Integer.toString(col) + ")" : ""); - } else if (issue.hasLocation()) { - loc = issue.getLocation().get(0).asStringValue(); - } else { - int line = ToolingExtensions.readIntegerExtension(issue, ToolingExtensions.EXT_ISSUE_LINE, -1); - int col = ToolingExtensions.readIntegerExtension(issue, ToolingExtensions.EXT_ISSUE_COL, -1); - loc = (line >= 0 && col >= 0 ? "line " + Integer.toString(line) + ", col" + Integer.toString(col) : "??"); - } - return " " + issue.getSeverity().getDisplay() + " @ " + loc + " : " + issue.getDetails().getText(); - } - } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/CliContext.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/CliContext.java index 63661c8fe..27942ef76 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/CliContext.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/CliContext.java @@ -4,6 +4,9 @@ import org.hl7.fhir.validation.Validator; import java.util.*; +/** + * A POJO for storing the flags/values for the CLI validator. + */ public class CliContext { private String map = null; @@ -26,8 +29,261 @@ public class CliContext { private String mapLog = null; private String lang = null; private String fhirpath = null; - private String snomedCT = "900000000000207008"; + private String snomedCT = SnomedVersion.INTL.getCode(); private String targetVer = null; private boolean doDebug = false; private boolean assumeValidRestReferences = false; + + public String getMap() { + return map; + } + + public CliContext setMap(String map) { + this.map = map; + return this; + } + + public List getIgs() { + return igs; + } + + public CliContext setIgs(List igs) { + this.igs = igs; + return this; + } + + public CliContext addIg(String ig) { + if (this.igs == null) { + this.igs = new ArrayList<>(); + } + this.igs.add(ig); + return this; + } + + public List getQuestionnaires() { + return questionnaires; + } + + public CliContext setQuestionnaires(List questionnaires) { + this.questionnaires = questionnaires; + return this; + } + + public CliContext addQuestionnaire(String questionnaire) { + if (this.questionnaires == null) { + this.questionnaires = new ArrayList<>(); + } + this.questionnaires.add(questionnaire); + return this; + } + + public String getTxServer() { + return txServer; + } + + public CliContext setTxServer(String txServer) { + this.txServer = txServer; + return this; + } + + public boolean isDoNative() { + return doNative; + } + + public CliContext setDoNative(boolean doNative) { + this.doNative = doNative; + return this; + } + + public boolean isAnyExtensionsAllowed() { + return anyExtensionsAllowed; + } + + public CliContext setAnyExtensionsAllowed(boolean anyExtensionsAllowed) { + this.anyExtensionsAllowed = anyExtensionsAllowed; + return this; + } + + public boolean isHintAboutNonMustSupport() { + return hintAboutNonMustSupport; + } + + public CliContext setHintAboutNonMustSupport(boolean hintAboutNonMustSupport) { + this.hintAboutNonMustSupport = hintAboutNonMustSupport; + return this; + } + + public boolean isRecursive() { + return recursive; + } + + public CliContext setRecursive(boolean recursive) { + this.recursive = recursive; + return this; + } + + public Locale getLocale() { + return locale; + } + + public CliContext setLocale(Locale locale) { + this.locale = locale; + return this; + } + + public List getProfiles() { + return profiles; + } + + public CliContext setProfiles(List profiles) { + this.profiles = profiles; + return this; + } + + public CliContext addProfile(String profile) { + if (this.profiles == null) { + this.profiles = new ArrayList<>(); + } + this.profiles.add(profile); + return this; + } + + public Validator.EngineMode getMode() { + return mode; + } + + public CliContext setMode(Validator.EngineMode mode) { + this.mode = mode; + return this; + } + + public String getOutput() { + return output; + } + + public CliContext setOutput(String output) { + this.output = output; + return this; + } + + public Boolean getCanDoNative() { + return canDoNative; + } + + public CliContext setCanDoNative(Boolean canDoNative) { + this.canDoNative = canDoNative; + return this; + } + + public List getSources() { + return sources; + } + + public CliContext setSources(List sources) { + this.sources = sources; + return this; + } + + public CliContext addSource(String source) { + if (this.sources == null) { + this.sources = new ArrayList<>(); + } + this.sources.add(source); + return this; + } + + public Map getLocations() { + return locations; + } + + public CliContext setLocations(Map locations) { + this.locations = locations; + return this; + } + + public CliContext addLocation(String profile, String location) { + this.locations.put(profile, location); + return this; + } + + public String getSv() { + return sv; + } + + public CliContext setSv(String sv) { + this.sv = sv; + return this; + } + + public String getTxLog() { + return txLog; + } + + public CliContext setTxLog(String txLog) { + this.txLog = txLog; + return this; + } + + public String getMapLog() { + return mapLog; + } + + public CliContext setMapLog(String mapLog) { + this.mapLog = mapLog; + return this; + } + + public String getLang() { + return lang; + } + + public CliContext setLang(String lang) { + this.lang = lang; + return this; + } + + public String getFhirpath() { + return fhirpath; + } + + public CliContext setFhirpath(String fhirpath) { + this.fhirpath = fhirpath; + return this; + } + + public String getSnomedCT() { + return snomedCT; + } + + public CliContext setSnomedCT(String snomedCT) { + this.snomedCT = SnomedVersion.resolveSnomedCTCode(snomedCT); + return this; + } + + public String getTargetVer() { + return targetVer; + } + + public CliContext setTargetVer(String targetVer) { + this.targetVer = targetVer; + return this; + } + + public boolean isDoDebug() { + return doDebug; + } + + public CliContext setDoDebug(boolean doDebug) { + this.doDebug = doDebug; + return this; + } + + public boolean isAssumeValidRestReferences() { + return assumeValidRestReferences; + } + + public CliContext setAssumeValidRestReferences(boolean assumeValidRestReferences) { + this.assumeValidRestReferences = assumeValidRestReferences; + return this; + } } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Utils.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Common.java similarity index 76% rename from org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Utils.java rename to org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Common.java index 37cd63218..0e3e9adde 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Utils.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Common.java @@ -1,19 +1,16 @@ package org.hl7.fhir.validation.cliutils; -import org.hl7.fhir.r5.context.SimpleWorkerContext; import org.hl7.fhir.r5.model.Constants; import org.hl7.fhir.r5.model.FhirPublication; -import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.validation.ValidationEngine; import java.io.File; -public class Utils { - +public class Common { public static String getVersion(String[] args) { - String v = ParamUtils.getParam(args, "-version"); + String v = Params.getParam(args, "-version"); if (v == null) { v = "current"; for (int i = 0; i < args.length; i++) { @@ -22,7 +19,7 @@ public class Utils { throw new Error("Specified -ig without indicating ig file"); else { String n = args[i + 1]; - v = Utils.getVersionFromIGName(v, n); + v = Common.getVersionFromIGName(v, n); } } } @@ -42,11 +39,11 @@ public class Utils { /** * Evaluates the current implementation guide file name and sets the current version accordingly. - * + *

* If igFileName is not one of the known patterns, will return whatever value is passed in as default. * * @param defaultValue Version to return if no associated version can be determined from passed in igFileName - * @param igFileName Name of the implementation guide + * @param igFileName Name of the implementation guide * @return */ public static String getVersionFromIGName(String defaultValue, String igFileName) { @@ -82,15 +79,15 @@ public class Utils { public static String getTerminologyServerLog(String[] args) { String txLog = null; - if (ParamUtils.hasParam(args, "-txLog")) { - txLog = ParamUtils.getParam(args, "-txLog"); + if (Params.hasParam(args, "-txLog")) { + txLog = Params.getParam(args, "-txLog"); new File(txLog).delete(); } return txLog; } public static ValidationEngine getValidationEngine(String[] args, String txLog) throws Exception { - String v = Utils.getVersion(args); + String v = Common.getVersion(args); String definitions = VersionUtilities.packageForVersion(v) + "#" + v; System.out.println("Loading (v = " + v + ", tx server http://tx.fhir.org)"); return new ValidationEngine(definitions, "http://tx.fhir.org", txLog, FhirPublication.fromCode(v), v); @@ -110,21 +107,4 @@ public class Utils { } } } - - private static Resource loadResource(String[] args, String param, SimpleWorkerContext context) { - String resString = ParamUtils.getParam(args, param); - Resource resource = context.fetchResource(Resource.class, resString); - if (resource == null) { - System.out.println("Unable to locate resource for " + param + ", " + resString); - } - return resource; - } - - public static Resource getRightResource(String[] args, SimpleWorkerContext context) { - return loadResource(args, "-right", context); - } - - public static Resource getLeftResource(String[] args, SimpleWorkerContext context) { - return loadResource(args, "-left", context); - } } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ComparisonUtils.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Comparison.java similarity index 87% rename from org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ComparisonUtils.java rename to org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Comparison.java index af39679c3..29612713e 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ComparisonUtils.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Comparison.java @@ -21,27 +21,27 @@ import java.io.FileOutputStream; import java.io.IOException; import java.util.UUID; -public class ComparisonUtils { +public class Comparison { public static void doLeftRightComparison(String[] args, String dest, ValidationEngine validator) throws IOException { // ok now set up the comparison - String left = ParamUtils.getParam(args, "-left"); - String right = ParamUtils.getParam(args, "-right"); + String left = Params.getParam(args, Params.LEFT); + String right = Params.getParam(args, Params.RIGHT); - Resource resLeft = validator.getContext().fetchResource(Resource.class, left); + Resource resLeft = validator.getContext().fetchResource(Resource.class, left); Resource resRight = validator.getContext().fetchResource(Resource.class, right); if (resLeft == null) { - System.out.println("Unable to locate left resource " +left); + System.out.println("Unable to locate left resource " + left); } if (resRight == null) { - System.out.println("Unable to locate right resource " +right); + System.out.println("Unable to locate right resource " + right); } if (resLeft != null && resRight != null) { if (resLeft instanceof StructureDefinition && resRight instanceof StructureDefinition) { - ComparisonUtils.compareStructureDefinitions(dest, validator, left, right, (StructureDefinition) resLeft, (StructureDefinition) resRight); + Comparison.compareStructureDefinitions(dest, validator, left, right, (StructureDefinition) resLeft, (StructureDefinition) resRight); } else if (resLeft instanceof CapabilityStatement && resRight instanceof CapabilityStatement) { - ComparisonUtils.compareCapabilityStatements(args, dest, validator, left, right, (CanonicalResource) resLeft, (CanonicalResource) resRight); + Comparison.compareCapabilityStatements(args, dest, validator, left, right, (CanonicalResource) resLeft, (CanonicalResource) resRight); } else System.out.println("Unable to compare left resource " + left + " (" + resLeft.fhirType() + ") with right resource " + right + " (" + resRight.fhirType() + ")"); } @@ -90,7 +90,7 @@ public class ComparisonUtils { } private static String chooseName(String[] args, String name, CanonicalResource mr) { - String s = ParamUtils.getParam(args, "-" + name); + String s = Params.getParam(args, "-" + name); if (Utilities.noString(s)) s = mr.present(); return s; diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/DisplayUtils.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Display.java similarity index 95% rename from org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/DisplayUtils.java rename to org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Display.java index f5a7f4c18..bb993edc7 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/DisplayUtils.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Display.java @@ -7,7 +7,7 @@ import org.hl7.fhir.utilities.cache.ToolsVersion; import java.io.IOException; -public class DisplayUtils { +public class Display { public static void printCliArgumentsAndInfo(String[] args) throws IOException { System.out.print("Arguments:"); @@ -27,8 +27,8 @@ public class DisplayUtils { System.out.println(""); System.out.println("The FHIR validation tool validates a FHIR resource or bundle."); 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("* 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"); @@ -43,8 +43,8 @@ public class DisplayUtils { 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(" 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"); diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ParamArg.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ParamArg.java deleted file mode 100644 index b27ac9050..000000000 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ParamArg.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.hl7.fhir.validation.cliutils; - -public enum ParamArg { - VERSION("-version"), - OUTPUT("-output"), - PROXY("-proxy"), - PROFILE("-profile"), - QUESTIONNAIRE("-questionnaire"), - NATIVE("-native"), - ASSUME_VALID_REST_REF("-assumeValidRestReferences"), - DEBUG("-debug"), - SCT("-sct"), - RECURSE("-recurse"), - LOCALE("-locale"), - STRICT_EXTENSIONS("-strictExtensions"), - HINT_ABOUT_NON_MUST_SUPPORT("-hintAboutNonMustSupport"), - TO_VERSION("-to-version"), - DO_NATIVE("-do-native"), - NO_NATIVE("-no-native"), - TRANSFORM("-transform"), - NARRATIVE("-narrative"), - SNAPSHOT("-snapshot"), - SCAN("-scan"), - TERMINOLOGY("-tx"), - TERMINOLOGY_LOG("-txLog"); - - private final String code; - - ParamArg(String code) { - this.code = code; - } - -} - - -// } else if (args[i].equals("-log")) { -// if (i + 1 == args.length) -// throw new Error("Specified -log without indicating file"); -// else -// mapLog = args[++i]; -// } else if (args[i].equals("-language")) { -// if (i + 1 == args.length) -// throw new Error("Specified -language without indicating language"); -// else -// lang = args[++i]; -// } else if (args[i].equals("-ig") || args[i].equals("-defn")) { -// if (i + 1 == args.length) -// throw new Error("Specified " + args[i] + " without indicating ig file"); -// else { -// String s = args[++i]; -// sv = Utils.getVersionFromIGName(null, s); -// if (sv == null) { -// igs.add(s); -// } -// } -// } else if (args[i].equals("-map")) { -// if (map == null) { -// if (i + 1 == args.length) -// throw new Error("Specified -map without indicating map file"); -// else -// map = args[++i]; -// } else { -// throw new Exception("Can only nominate a single -map parameter"); -// } -// } else if (args[i].startsWith("-x")) { -// i++; -// } else if (args[i].equals("-convert")) { -// mode = EngineMode.CONVERT; -// } else if (args[i].equals("-fhirpath")) { -// mode = EngineMode.FHIRPATH; -// if (fhirpath == null) -// if (i + 1 == args.length) -// throw new Error("Specified -fhirpath without indicating a FHIRPath expression"); -// else -// fhirpath = args[++i]; -// else -// throw new Exception("Can only nominate a single -fhirpath parameter"); -// } else { -// sources.add(args[i]); -// } -// } \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ParamUtils.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ParamUtils.java deleted file mode 100644 index 32913524d..000000000 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ParamUtils.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.hl7.fhir.validation.cliutils; - -import java.util.Arrays; - -public class ParamUtils { - - /** - * Checks the list of passed in params to see if it contains the passed in param. - * - * @param args Array of params to search. - * @param param {@link String} param to search for. - * @return {@link Boolean#TRUE} if the list contains the given param. - */ - public static boolean hasParam(String[] args, String param) { - return Arrays.asList(args).contains(param); - } - - /** - * Fetches the vlaue for the passed in param from the provided list of params. - * - * @param args Array of params to search. - * @param param {@link String} param keyword to search for. - * @return {@link String} value for the provided param. - */ - public static String getParam(String[] args, String param) { - for (int i = 0; i < args.length - 1; i++) - if (args[i].equals(param)) - return args[i + 1]; - return null; - } - -} diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Params.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Params.java new file mode 100644 index 000000000..cb9927640 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Params.java @@ -0,0 +1,210 @@ +package org.hl7.fhir.validation.cliutils; + +import org.hl7.fhir.utilities.VersionUtilities; +import org.hl7.fhir.validation.Validator; + +import java.util.Arrays; +import java.util.Locale; + +public class Params { + + public static final String VERSION = "-version"; + public static final String OUTPUT = "-output"; + public static final String PROXY = "-proxy"; + public static final String PROFILE = "-profile"; + public static final String QUESTIONNAIRE = "-questionnaire"; + public static final String NATIVE = "-native"; + public static final String ASSUME_VALID_REST_REF = "-assumeValidRestReferences"; + public static final String DEBUG = "-debug"; + public static final String SCT = "-sct"; + public static final String RECURSE = "-recurse"; + public static final String LOCALE = "-locale"; + public static final String STRICT_EXTENSIONS = "-strictExtensions"; + public static final String HINT_ABOUT_NON_MUST_SUPPORT = "-hintAboutNonMustSupport"; + public static final String TO_VERSION = "-to-version"; + public static final String DO_NATIVE = "-do-native"; + public static final String NO_NATIVE = "-no-native"; + public static final String TRANSFORM = "-transform"; + public static final String NARRATIVE = "-narrative"; + public static final String SNAPSHOT = "-snapshot"; + public static final String SCAN = "-scan"; + public static final String TERMINOLOGY = "-tx"; + public static final String TERMINOLOGY_LOG = "-txLog"; + public static final String LOG = "-log"; + public static final String LANGUAGE = "-language"; + public static final String IMPLEMENTATION_GUIDE = "-ig"; + public static final String DEFINITION = "defn"; + public static final String MAP = "-map"; + public static final String X = "-x"; + public static final String CONVERT = "-convert"; + public static final String FHIRPATH = "-fhirpath"; + public static final String TEST = "-tests"; + public static final String HELP = "help"; + public static final String COMPARE = "-compare"; + public static final String DESTINATION = "-dest"; + public static final String LEFT = "-left"; + public static final String RIGHT = "-right"; + + /** + * Checks the list of passed in params to see if it contains the passed in param. + * + * @param args Array of params to search. + * @param param {@link String} param to search for. + * @return {@link Boolean#TRUE} if the list contains the given param. + */ + public static boolean hasParam(String[] args, String param) { + return Arrays.asList(args).contains(param); + } + + /** + * Fetches the vlaue for the passed in param from the provided list of params. + * + * @param args Array of params to search. + * @param param {@link String} param keyword to search for. + * @return {@link String} value for the provided param. + */ + public static String getParam(String[] args, String param) { + for (int i = 0; i < args.length - 1; i++) + if (args[i].equals(param)) + return args[i + 1]; + return null; + } + + /** + * TODO Don't do this all in one for loop. + * + * @param args + * @return + * @throws Exception + */ + public static CliContext loadCliContext(String[] args) throws Exception { + CliContext cliContext = new CliContext(); + + // load the parameters - so order doesn't matter + for (int i = 0; i < args.length; i++) { + if (args[i].equals(VERSION)) { + cliContext.setSv(VersionUtilities.getCurrentPackageVersion(args[++i])); + } else if (args[i].equals(OUTPUT)) { + if (i + 1 == args.length) + throw new Error("Specified -output without indicating output file"); + else + cliContext.setOutput(args[++i]); + } else if (args[i].equals(PROXY)) { + i++; // ignore next parameter + } else if (args[i].equals(PROFILE)) { + String p = null; + if (i + 1 == args.length) + throw new Error("Specified -profile without indicating profile source"); + else { + p = args[++i]; + cliContext.addProfile(args[++i]); + } + if (p != null && i + 1 < args.length && args[i + 1].equals("@")) { + i++; + if (i + 1 == args.length) + throw new Error("Specified -profile with @ without indicating profile location"); + else + cliContext.addLocation(p, args[++i]); + } + } else if (args[i].equals(QUESTIONNAIRE)) { + if (i + 1 == args.length) + throw new Error("Specified -questionnaire without indicating questionnaire file"); + else + cliContext.addQuestionnaire(args[++i]); + } else if (args[i].equals(NATIVE)) { + cliContext.setDoNative(true); + } else if (args[i].equals(ASSUME_VALID_REST_REF)) { + cliContext.setAssumeValidRestReferences(true); + } else if (args[i].equals(DEBUG)) { + cliContext.setDoDebug(true); + } else if (args[i].equals(SCT)) { + cliContext.setSnomedCT(args[++i]); + } else if (args[i].equals(RECURSE)) { + cliContext.setRecursive(true); + } else if (args[i].equals(LOCALE)) { + if (i + 1 == args.length) { + throw new Error("Specified -locale without indicating locale"); + } else { + cliContext.setLocale(new Locale(args[++i])); + } + } else if (args[i].equals(STRICT_EXTENSIONS)) { + cliContext.setAnyExtensionsAllowed(false); + } else if (args[i].equals(HINT_ABOUT_NON_MUST_SUPPORT)) { + cliContext.setHintAboutNonMustSupport(true); + } else if (args[i].equals(TO_VERSION)) { + cliContext.setTargetVer(args[++i]); + cliContext.setMode(Validator.EngineMode.VERSION); + } else if (args[i].equals(DO_NATIVE)) { + cliContext.setCanDoNative(true); + } else if (args[i].equals(NO_NATIVE)) { + cliContext.setCanDoNative(false); + } else if (args[i].equals(TRANSFORM)) { + cliContext.setMap(args[++i]); + cliContext.setMode(Validator.EngineMode.TRANSFORM); + } else if (args[i].equals(NARRATIVE)) { + cliContext.setMode(Validator.EngineMode.NARRATIVE); + } else if (args[i].equals(SNAPSHOT)) { + cliContext.setMode(Validator.EngineMode.SNAPSHOT); + } else if (args[i].equals(SCAN)) { + cliContext.setMode(Validator.EngineMode.SCAN); + } else if (args[i].equals(TERMINOLOGY)) { + if (i + 1 == args.length) + throw new Error("Specified -tx without indicating terminology server"); + else + cliContext.setTxServer("n/a".equals(args[++i]) ? null : args[i]); + } else if (args[i].equals(TERMINOLOGY_LOG)) { + if (i + 1 == args.length) + throw new Error("Specified -txLog without indicating file"); + else + cliContext.setTxLog(args[++i]); + } else if (args[i].equals(LOG)) { + if (i + 1 == args.length) + throw new Error("Specified -log without indicating file"); + else + cliContext.setMapLog(args[++i]); + } else if (args[i].equals(LANGUAGE)) { + if (i + 1 == args.length) + throw new Error("Specified -language without indicating language"); + else + cliContext.setLang(args[++i]); + } else if (args[i].equals(IMPLEMENTATION_GUIDE) || args[i].equals(DEFINITION)) { + if (i + 1 == args.length) + throw new Error("Specified " + args[i] + " without indicating ig file"); + else { + String s = args[++i]; + cliContext.setSv(Common.getVersionFromIGName(null, s)); + if (cliContext.getSv() == null) { + cliContext.addIg(s); + } + } + } else if (args[i].equals(MAP)) { + if (cliContext.getMap() == null) { + if (i + 1 == args.length) + throw new Error("Specified -map without indicating map file"); + else + cliContext.setMap(args[++i]); + } else { + throw new Exception("Can only nominate a single -map parameter"); + } + } else if (args[i].startsWith(X)) { + i++; + } else if (args[i].equals(CONVERT)) { + cliContext.setMode(Validator.EngineMode.CONVERT); + } else if (args[i].equals(FHIRPATH)) { + cliContext.setMode(Validator.EngineMode.FHIRPATH); + if (cliContext.getFhirpath() == null) + if (i + 1 == args.length) + throw new Error("Specified -fhirpath without indicating a FHIRPath expression"); + else + cliContext.setFhirpath(args[++i]); + else + throw new Exception("Can only nominate a single -fhirpath parameter"); + } else { + cliContext.addSource(args[i]); + } + } + if (cliContext.getSources().isEmpty()) + throw new Exception("Must provide at least one source file"); + return cliContext; + } +} diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/SnomedVersion.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/SnomedVersion.java index ea26fbfa6..f18112090 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/SnomedVersion.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/SnomedVersion.java @@ -24,6 +24,14 @@ public enum SnomedVersion { this.code = code; } + public String getLang() { + return lang; + } + + public String getCode() { + return code; + } + public static String resolveSnomedCTCode(String s) { String foundCode; Optional opt = Arrays.stream(values()) diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ValidationUtils.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ValidationUtils.java new file mode 100644 index 000000000..a5141ce14 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ValidationUtils.java @@ -0,0 +1,198 @@ +package org.hl7.fhir.validation.cliutils; + +import org.hl7.fhir.r5.elementmodel.Manager; +import org.hl7.fhir.r5.formats.IParser; +import org.hl7.fhir.r5.formats.JsonParser; +import org.hl7.fhir.r5.formats.XmlParser; +import org.hl7.fhir.r5.model.*; +import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.utilities.TextFile; +import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.validation.ValidationEngine; + +import java.io.File; +import java.io.FileOutputStream; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class ValidationUtils { + public static void validateSources(CliContext cliContext, ValidationEngine validator) throws Exception { + if (cliContext.getProfiles().size() > 0) + System.out.println(" .. validate " + cliContext.getSources() + " against " + cliContext.getProfiles().toString()); + else + System.out.println(" .. validate " + cliContext.getSources()); + validator.prepare(); // generate any missing snapshots + Resource r = validator.validate(cliContext.getSources(), cliContext.getProfiles()); + int ec = 0; + if (cliContext.getOutput() == null) { + if (r instanceof Bundle) + for (Bundle.BundleEntryComponent e : ((Bundle) r).getEntry()) + ec = displayOperationOutcome((OperationOutcome) e.getResource()) + ec; + else + ec = displayOperationOutcome((OperationOutcome) r); + } else { + IParser x; + if (cliContext.getOutput() != null && cliContext.getOutput().endsWith(".json")) { + x = new JsonParser(); + } else { + x = new XmlParser(); + } + x.setOutputStyle(IParser.OutputStyle.PRETTY); + FileOutputStream s = new FileOutputStream(cliContext.getOutput()); + x.compose(s, r); + s.close(); + } + 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 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 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 { + validator.convert(cliContext.getSources().get(0), cliContext.getOutput()); + System.out.println(" ...convert"); + } + + public static void evaluateFhirpath(CliContext cliContext, ValidationEngine validator) throws Exception { + System.out.println(" ...evaluating " + cliContext.getFhirpath()); + System.out.println(validator.evaluateFhirPath(cliContext.getSources().get(0), cliContext.getFhirpath())); + } + + public static void generateSnapshot(CliContext cliContext, ValidationEngine validator) throws Exception { + StructureDefinition r = validator.snapshot(cliContext.getSources().get(0), cliContext.getSv()); + System.out.println(" ...generated snapshot successfully"); + if (cliContext.getOutput() != null) { + validator.handleOutput(r, cliContext.getOutput(), cliContext.getSv()); + } + } + + public static void generateNarrative(CliContext cliContext, ValidationEngine validator) throws Exception { + DomainResource r = validator.generate(cliContext.getSources().get(0), cliContext.getSv()); + System.out.println(" ...generated narrative successfully"); + if (cliContext.getOutput() != null) { + validator.handleOutput(r, cliContext.getOutput(), cliContext.getSv()); + } + } + + public static void transform(CliContext cliContext, ValidationEngine validator) throws Exception { + if (cliContext.getSources().size() > 1) + throw new Exception("Can only have one source when doing a transform (found " + cliContext.getSources() + ")"); + if (cliContext.getTxServer() == null) + throw new Exception("Must provide a terminology server when doing a transform"); + if (cliContext.getMap() == null) + throw new Exception("Must provide a map when doing a transform"); + try { + validator.setMapLog(cliContext.getMapLog()); + org.hl7.fhir.r5.elementmodel.Element r = validator.transform(cliContext.getSources().get(0), cliContext.getMap()); + System.out.println(" ...success"); + if (cliContext.getOutput() != null) { + FileOutputStream s = new FileOutputStream(cliContext.getOutput()); + if (cliContext.getOutput() != null && cliContext.getOutput().endsWith(".json")) + new org.hl7.fhir.r5.elementmodel.JsonParser(validator.getContext()).compose(r, s, IParser.OutputStyle.PRETTY, null); + else + new org.hl7.fhir.r5.elementmodel.XmlParser(validator.getContext()).compose(r, s, IParser.OutputStyle.PRETTY, null); + s.close(); + } + } catch (Exception e) { + System.out.println(" ...Failure: " + e.getMessage()); + e.printStackTrace(); + } + } + + public static void transformVersion(CliContext cliContext, ValidationEngine validator) throws Exception { + if (cliContext.getSources().size() > 1) { + throw new Exception("Can only have one source when converting versions (found " + cliContext.getSources() + ")"); + } + if (cliContext.getTargetVer() == null) { + throw new Exception("Must provide a map when converting versions"); + } + if (cliContext.getOutput() == null) { + throw new Exception("Must nominate an output when converting versions"); + } + try { + if (cliContext.getMapLog() != null) { + validator.setMapLog(cliContext.getMapLog()); + } + byte[] r = validator.transformVersion(cliContext.getSources().get(0), cliContext.getTargetVer(), cliContext.getOutput().endsWith(".json") ? Manager.FhirFormat.JSON : Manager.FhirFormat.XML, cliContext.getCanDoNative()); + System.out.println(" ...success"); + TextFile.bytesToFile(r, cliContext.getOutput()); + } catch (Exception e) { + System.out.println(" ...Failure: " + e.getMessage()); + e.printStackTrace(); + } + } + + public static ValidationEngine getValidator(CliContext cliContext, String definitions) throws Exception { + System.out.println(" .. FHIR Version " + cliContext.getSv() + ", definitions from " + definitions); + System.out.println(" .. connect to tx server @ " + cliContext.getTxServer()); + ValidationEngine validator = new ValidationEngine(definitions, cliContext.getTxServer(), cliContext.getTxLog(), FhirPublication.fromCode(cliContext.getSv()), cliContext.getSv()); + validator.setDebug(cliContext.isDoDebug()); + System.out.println(" (v" + validator.getContext().getVersion() + ")"); + for (String src : cliContext.getIgs()) { + System.out.println("+ .. load IG from " + src); + validator.loadIg(src, cliContext.isRecursive()); + } + validator.setQuestionnaires(cliContext.getQuestionnaires()); + validator.setNative(cliContext.isDoNative()); + validator.setHintAboutNonMustSupport(cliContext.isHintAboutNonMustSupport()); + validator.setAnyExtensionsAllowed(cliContext.isAnyExtensionsAllowed()); + validator.setLanguage(cliContext.getLang()); + validator.setLocale(cliContext.getLocale()); + validator.setSnomedExtension(cliContext.getSnomedCT()); + validator.setAssumeValidRestReferences(cliContext.isAssumeValidRestReferences()); + return validator; + } + + public static int displayOperationOutcome(OperationOutcome oo) { + int error = 0; + int warn = 0; + int info = 0; + String file = ToolingExtensions.readStringExtension(oo, ToolingExtensions.EXT_OO_FILE); + + for (OperationOutcome.OperationOutcomeIssueComponent issue : oo.getIssue()) { + if (issue.getSeverity() == OperationOutcome.IssueSeverity.FATAL || issue.getSeverity() == OperationOutcome.IssueSeverity.ERROR) + error++; + else if (issue.getSeverity() == OperationOutcome.IssueSeverity.WARNING) + warn++; + else + info++; + } + + System.out.println((error == 0 ? "Success..." : "*FAILURE* ") + "validating " + file + ": " + " error:" + Integer.toString(error) + " warn:" + Integer.toString(warn) + " info:" + Integer.toString(info)); + for (OperationOutcome.OperationOutcomeIssueComponent issue : oo.getIssue()) { + System.out.println(getIssueSummary(issue)); + } + System.out.println(); + return error; + } + + private static String getIssueSummary(OperationOutcome.OperationOutcomeIssueComponent issue) { + String loc = null; + if (issue.hasExpression()) { + int line = ToolingExtensions.readIntegerExtension(issue, ToolingExtensions.EXT_ISSUE_LINE, -1); + int col = ToolingExtensions.readIntegerExtension(issue, ToolingExtensions.EXT_ISSUE_COL, -1); + loc = issue.getExpression().get(0).asStringValue() + (line >= 0 && col >= 0 ? " (line " + Integer.toString(line) + ", col" + Integer.toString(col) + ")" : ""); + } else if (issue.hasLocation()) { + loc = issue.getLocation().get(0).asStringValue(); + } else { + int line = ToolingExtensions.readIntegerExtension(issue, ToolingExtensions.EXT_ISSUE_LINE, -1); + int col = ToolingExtensions.readIntegerExtension(issue, ToolingExtensions.EXT_ISSUE_COL, -1); + loc = (line >= 0 && col >= 0 ? "line " + Integer.toString(line) + ", col" + Integer.toString(col) : "??"); + } + return " " + issue.getSeverity().getDisplay() + " @ " + loc + " : " + issue.getDetails().getText(); + } +} From 7affad01fca5aae55e0a387825e13eb2f5d62c27 Mon Sep 17 00:00:00 2001 From: markiantorno Date: Fri, 3 Apr 2020 14:12:47 -0400 Subject: [PATCH 4/4] Cleanup --- .../org/hl7/fhir/validation/Validator.java | 6 ++-- .../{cliutils => cli}/CliContext.java | 2 +- .../validation/{cliutils => cli}/Common.java | 27 +------------- .../{cliutils => cli}/Comparison.java | 2 +- .../validation/{cliutils => cli}/Display.java | 7 +++- .../validation/{cliutils => cli}/Params.java | 35 +++++++++++++++---- .../{cliutils => cli}/SnomedVersion.java | 2 +- .../{cliutils => cli}/ValidationUtils.java | 3 +- 8 files changed, 43 insertions(+), 41 deletions(-) rename org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/{cliutils => cli}/CliContext.java (99%) rename org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/{cliutils => cli}/Common.java (80%) rename org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/{cliutils => cli}/Comparison.java (99%) rename org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/{cliutils => cli}/Display.java (98%) rename org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/{cliutils => cli}/Params.java (90%) rename org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/{cliutils => cli}/SnomedVersion.java (96%) rename org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/{cliutils => cli}/ValidationUtils.java (99%) diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Validator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Validator.java index bc4241fde..c98dbfdde 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Validator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Validator.java @@ -54,7 +54,7 @@ import org.hl7.fhir.r5.model.ImplementationGuide; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; -import org.hl7.fhir.validation.cliutils.*; +import org.hl7.fhir.validation.cli.*; /** * A executable class that will validate one or more FHIR resources against @@ -114,9 +114,9 @@ public class Validator { System.out.println("Specified destination (-dest parameter) is not valid: \"" + dest + "\")"); else { // first, prepare the context - String txLog = Common.getTerminologyServerLog(args); + String txLog = Params.getTerminologyServerLog(args); ValidationEngine validator = Common.getValidationEngine(args, txLog); - Common.checkIGFileReferences(args); + Params.checkIGFileReferences(args); Comparison.doLeftRightComparison(args, dest, validator); } } else { diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/CliContext.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/CliContext.java similarity index 99% rename from org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/CliContext.java rename to org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/CliContext.java index 27942ef76..3df25408a 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/CliContext.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/CliContext.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.validation.cliutils; +package org.hl7.fhir.validation.cli; import org.hl7.fhir.validation.Validator; diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Common.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/Common.java similarity index 80% rename from org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Common.java rename to org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/Common.java index 0e3e9adde..66e617399 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Common.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/Common.java @@ -1,12 +1,10 @@ -package org.hl7.fhir.validation.cliutils; +package org.hl7.fhir.validation.cli; import org.hl7.fhir.r5.model.Constants; import org.hl7.fhir.r5.model.FhirPublication; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.validation.ValidationEngine; -import java.io.File; - public class Common { public static String getVersion(String[] args) { @@ -77,15 +75,6 @@ public class Common { } } - public static String getTerminologyServerLog(String[] args) { - String txLog = null; - if (Params.hasParam(args, "-txLog")) { - txLog = Params.getParam(args, "-txLog"); - new File(txLog).delete(); - } - return txLog; - } - public static ValidationEngine getValidationEngine(String[] args, String txLog) throws Exception { String v = Common.getVersion(args); String definitions = VersionUtilities.packageForVersion(v) + "#" + v; @@ -93,18 +82,4 @@ public class Common { return new ValidationEngine(definitions, "http://tx.fhir.org", txLog, FhirPublication.fromCode(v), v); } - public static void checkIGFileReferences(String[] args) { - for (int i = 0; i < args.length; i++) { - if ("-ig".equals(args[i])) { - if (i + 1 == args.length) - throw new Error("Specified -ig without indicating ig file"); - else { - String s = args[++i]; - if (!s.startsWith("hl7.fhir.core-")) { - System.out.println("Load Package: " + s); - } - } - } - } - } } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Comparison.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/Comparison.java similarity index 99% rename from org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Comparison.java rename to org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/Comparison.java index 29612713e..2ae398529 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Comparison.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/Comparison.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.validation.cliutils; +package org.hl7.fhir.validation.cli; import org.hl7.fhir.r5.conformance.CapabilityStatementUtilities; import org.hl7.fhir.r5.conformance.ProfileComparer; diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Display.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/Display.java similarity index 98% rename from org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Display.java rename to org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/Display.java index bb993edc7..4bfda8ecc 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Display.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/Display.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.validation.cliutils; +package org.hl7.fhir.validation.cli; import org.hl7.fhir.r5.model.Constants; import org.hl7.fhir.utilities.VersionUtilities; @@ -7,6 +7,11 @@ import org.hl7.fhir.utilities.cache.ToolsVersion; import java.io.IOException; +/** + * Class for displaying output to the cli user. + * + * TODO - Clean this up for localization + */ public class Display { public static void printCliArgumentsAndInfo(String[] args) throws IOException { diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Params.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/Params.java similarity index 90% rename from org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Params.java rename to org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/Params.java index cb9927640..59f57212e 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/Params.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/Params.java @@ -1,8 +1,9 @@ -package org.hl7.fhir.validation.cliutils; +package org.hl7.fhir.validation.cli; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.validation.Validator; +import java.io.File; import java.util.Arrays; import java.util.Locale; @@ -57,7 +58,7 @@ public class Params { } /** - * Fetches the vlaue for the passed in param from the provided list of params. + * Fetches the value for the passed in param from the provided list of params. * * @param args Array of params to search. * @param param {@link String} param keyword to search for. @@ -71,11 +72,7 @@ public class Params { } /** - * TODO Don't do this all in one for loop. - * - * @param args - * @return - * @throws Exception + * TODO Don't do this all in one for loop. Use the above methods. */ public static CliContext loadCliContext(String[] args) throws Exception { CliContext cliContext = new CliContext(); @@ -207,4 +204,28 @@ public class Params { throw new Exception("Must provide at least one source file"); return cliContext; } + + public static String getTerminologyServerLog(String[] args) { + String txLog = null; + if (hasParam(args, "-txLog")) { + txLog = getParam(args, "-txLog"); + new File(txLog).delete(); + } + return txLog; + } + + public static void checkIGFileReferences(String[] args) { + for (int i = 0; i < args.length; i++) { + if (IMPLEMENTATION_GUIDE.equals(args[i])) { + if (i + 1 == args.length) + throw new Error("Specified -ig without indicating ig file"); + else { + String s = args[++i]; + if (!s.startsWith("hl7.fhir.core-")) { + System.out.println("Load Package: " + s); + } + } + } + } + } } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/SnomedVersion.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/SnomedVersion.java similarity index 96% rename from org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/SnomedVersion.java rename to org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/SnomedVersion.java index f18112090..84a33a65e 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/SnomedVersion.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/SnomedVersion.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.validation.cliutils; +package org.hl7.fhir.validation.cli; import java.util.Arrays; import java.util.Optional; diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ValidationUtils.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/ValidationUtils.java similarity index 99% rename from org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ValidationUtils.java rename to org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/ValidationUtils.java index a5141ce14..7d0fc466f 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cliutils/ValidationUtils.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/ValidationUtils.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.validation.cliutils; +package org.hl7.fhir.validation.cli; import org.hl7.fhir.r5.elementmodel.Manager; import org.hl7.fhir.r5.formats.IParser; @@ -17,6 +17,7 @@ import java.util.List; import java.util.Set; public class ValidationUtils { + public static void validateSources(CliContext cliContext, ValidationEngine validator) throws Exception { if (cliContext.getProfiles().size() > 0) System.out.println(" .. validate " + cliContext.getSources() + " against " + cliContext.getProfiles().toString());