diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/test/utils/TestingUtilities.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/test/utils/TestingUtilities.java index 62999b83d..00bc0fb47 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/test/utils/TestingUtilities.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/test/utils/TestingUtilities.java @@ -88,13 +88,10 @@ public class TestingUtilities { if (!Utilities.noString(s)) return s; s = "C:\\work\\org.hl7.fhir\\build"; - // FIXME: change this back - s = "/Users/jamesagnew/git/fhir"; if (new File(s).exists()) return s; throw new Error("FHIR Home directory not configured"); } - public static String content() throws IOException { if (contentpath != null) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Manager.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Manager.java index 7ec051cbc..1fde2d4fe 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Manager.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Manager.java @@ -24,6 +24,9 @@ package org.hl7.fhir.r5.elementmodel; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Map; import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.FHIRException; @@ -34,23 +37,41 @@ import org.hl7.fhir.r5.model.StructureDefinition; public class Manager { + //TODO use EnumMap public enum FhirFormat { XML, JSON, TURTLE, TEXT, VBAR; public String getExtension() { switch (this) { - case JSON: - return "json"; - case TURTLE: - return "ttl"; - case XML: - return "xml"; - case TEXT: - return "txt"; - case VBAR: - return "hl7"; + case JSON: + return "json"; + case TURTLE: + return "ttl"; + case XML: + return "xml"; + case TEXT: + return "txt"; + case VBAR: + return "hl7"; } return null; } + + public static FhirFormat getFhirFormat(String code) { + switch (code) { + case "json": + return JSON; + case "ttl": + return TURTLE; + case "xml": + return XML; + case "txt": + return TEXT; + case "hl7": + return VBAR; + } + return null; + } + } public static Element parse(IWorkerContext context, InputStream source, FhirFormat inputFormat) throws FHIRFormatError, DefinitionException, IOException, FHIRException { diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/validation/ValidationMessage.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/validation/ValidationMessage.java index 862961b3e..f93bfdba4 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/validation/ValidationMessage.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/validation/ValidationMessage.java @@ -51,6 +51,7 @@ package org.hl7.fhir.utilities.validation; */ import java.util.Comparator; +import java.util.EnumMap; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; diff --git a/org.hl7.fhir.validation/pom.xml b/org.hl7.fhir.validation/pom.xml index e9e7c1ea8..9bf6bac5c 100644 --- a/org.hl7.fhir.validation/pom.xml +++ b/org.hl7.fhir.validation/pom.xml @@ -12,6 +12,10 @@ org.hl7.fhir.validation bundle + + 1.3.4 + + @@ -138,6 +142,48 @@ ${validator_test_case_version} test + + + io.javalin + javalin + 3.8.0 + + + org.slf4j + slf4j-simple + 1.7.28 + + + + com.fasterxml.jackson.core + jackson-databind + 2.10.3 + + + org.thymeleaf + thymeleaf + 3.0.9.RELEASE + + + org.junit.jupiter + junit-jupiter + RELEASE + test + + + + + org.seleniumhq.selenium + selenium-chrome-driver + 3.141.59 + test + + + io.github.bonigarcia + webdrivermanager + 3.6.2 + test + @@ -151,5 +197,4 @@ - diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java index 53237c8d0..0d76dfa8d 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java @@ -1068,6 +1068,13 @@ public class ValidationEngine implements IValidatorResourceFetcher { return isBundle; } + public OperationOutcome validate(byte[] source, FhirFormat cntType, List profiles) throws Exception { + List messages = new ArrayList(); + InstanceValidator validator = getValidator(); + validator.validate(null, messages, new ByteArrayInputStream(source), cntType, asSdList(profiles)); + return messagesToOutcome(messages); + } + public OperationOutcome validate(String location, byte[] source, FhirFormat cntType, List profiles) throws Exception { List messages = new ArrayList(); if (doNative) { 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 c98dbfdde..8abac8da5 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 @@ -49,12 +49,17 @@ POSSIBILITY OF SUCH DAMAGE. */ import java.io.File; +import java.net.URI; import org.hl7.fhir.r5.model.ImplementationGuide; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; -import org.hl7.fhir.validation.cli.*; +import org.hl7.fhir.validation.cli.ValidatorGui; +import org.hl7.fhir.validation.cli.services.ComparisonService; +import org.hl7.fhir.validation.cli.services.ValidationService; +import org.hl7.fhir.validation.cli.model.CliContext; +import org.hl7.fhir.validation.cli.utils.*; /** * A executable class that will validate one or more FHIR resources against @@ -75,6 +80,8 @@ public class Validator { VALIDATION, TRANSFORM, NARRATIVE, SNAPSHOT, SCAN, CONVERT, FHIRPATH, VERSION } + private static CliContext cliContext; + private static String getNamedParam(String[] args, String param) { boolean found = false; for (String a : args) { @@ -91,7 +98,29 @@ public class Validator { return Long.toString(maxMemory / (1024 * 1024)); } + private static CliContext getCliContext() { + if (cliContext == null) { + cliContext = new CliContext(); + } + return cliContext; + } + + private static void goToWebPage(String url) { + try { + + URI uri= new URI(url); + + java.awt.Desktop.getDesktop().browse(uri); + System.out.println("Web page opened in browser"); + + } catch (Exception e) { + + e.printStackTrace(); + } + } + public static void main(String[] args) throws Exception { + 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, Params.PROXY); @@ -101,7 +130,13 @@ public class Validator { System.setProperty("http.proxyPort", p[1]); } - if (Params.hasParam(args, Params.TEST)) { + if (Params.hasParam(args, Params.GUI)) { + cliContext = Params.loadCliContext(args); + String v = Common.getVersion(args); + String definitions = VersionUtilities.packageForVersion(v) + "#" + v; + ValidationEngine validationEngine = Common.getValidationEngine(v, definitions, cliContext.getTxLog()); + ValidatorGui.start(cliContext, validationEngine, true); + } else 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(); @@ -115,30 +150,32 @@ public class Validator { else { // first, prepare the context String txLog = Params.getTerminologyServerLog(args); - ValidationEngine validator = Common.getValidationEngine(args, txLog); + String v = Common.getVersion(args); + String definitions = VersionUtilities.packageForVersion(v) + "#" + v; + ValidationEngine validator = Common.getValidationEngine(v, definitions, txLog); Params.checkIGFileReferences(args); - Comparison.doLeftRightComparison(args, dest, validator); + ComparisonService.doLeftRightComparison(args, dest, validator); } } else { Display.printCliArgumentsAndInfo(args); - CliContext cliContext = Params.loadCliContext(args); + 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(cliContext.getSv()) + "#" + VersionUtilities.getCurrentVersion(cliContext.getSv()); - ValidationEngine validator = ValidationUtils.getValidator(cliContext, definitions); - + ValidationEngine validator = ValidationService.getValidator(cliContext, definitions); if (cliContext.getMode() == EngineMode.VERSION) { - ValidationUtils.transformVersion(cliContext, validator); + + ValidationService.transformVersion(cliContext, validator); } else if (cliContext.getMode() == EngineMode.TRANSFORM) { - ValidationUtils.transform(cliContext, validator); + ValidationService.transform(cliContext, validator); } else if (cliContext.getMode() == EngineMode.NARRATIVE) { - ValidationUtils.generateNarrative(cliContext, validator); + ValidationService.generateNarrative(cliContext, validator); } else if (cliContext.getMode() == EngineMode.SNAPSHOT) { - ValidationUtils.generateSnapshot(cliContext, validator); + ValidationService.generateSnapshot(cliContext, validator); } else if (cliContext.getMode() == EngineMode.CONVERT) { - ValidationUtils.convertSources(cliContext, validator); + ValidationService.convertSources(cliContext, validator); } else if (cliContext.getMode() == EngineMode.FHIRPATH) { - ValidationUtils.evaluateFhirpath(cliContext, validator); + ValidationService.evaluateFhirpath(cliContext, validator); } else { if (definitions == null) { throw new Exception("Must provide a defn when doing validation"); @@ -150,9 +187,9 @@ public class Validator { } } if (cliContext.getMode() == EngineMode.SCAN) { - ValidationUtils.validateScan(cliContext, validator); + ValidationService.validateScan(cliContext, validator); } else { - ValidationUtils.validateSources(cliContext, validator); + ValidationService.validateSources(cliContext, validator); } } } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/RestEndpoints.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/RestEndpoints.java new file mode 100644 index 000000000..055515301 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/RestEndpoints.java @@ -0,0 +1,29 @@ +package org.hl7.fhir.validation.cli; + +import io.javalin.Javalin; +import org.hl7.fhir.validation.ValidationEngine; +import org.hl7.fhir.validation.cli.controller.CliContextController; +import org.hl7.fhir.validation.cli.controller.ValidationController; +import org.hl7.fhir.validation.cli.controller.UIController; +import org.hl7.fhir.validation.cli.model.CliContext; + +public class RestEndpoints { + + public UIController myUIController; + public CliContextController myCliContextController; + public ValidationController myValidationController; + + public void initRestEndpoints(Javalin app, CliContext cliContext, ValidationEngine validationEngine) { + + myUIController = new UIController(); + myCliContextController = new CliContextController(cliContext); + myValidationController = new ValidationController(validationEngine); + + app.get("/home", myUIController.renderLandingPage); + + app.get("/context", myCliContextController::handleGetCurrentCliContext); + app.post("/context", myCliContextController::handleSetCurrentCliContext); + + app.post("/validate", myValidationController::handleValidationRequest); + } +} diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/ValidatorGui.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/ValidatorGui.java new file mode 100644 index 000000000..3030d0e2e --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/ValidatorGui.java @@ -0,0 +1,60 @@ +package org.hl7.fhir.validation.cli; + +import io.javalin.Javalin; +import org.hl7.fhir.utilities.VersionUtilities; +import org.hl7.fhir.validation.ValidationEngine; +import org.hl7.fhir.validation.cli.model.CliContext; +import org.hl7.fhir.validation.cli.utils.Common; + +import java.awt.*; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; + +public class ValidatorGui { + + private static final int GUI_FRONTEND_PORT = 8080; + private static final String PAGE_ADDRESS = "http://localhost:" + GUI_FRONTEND_PORT + "/home"; + private static final String WEB_APP_FILE_LOCATION = "/public"; + private static Javalin app; + + private ValidatorGui(){} + + /** + * N.B. this entry point, is only for testing. Please start from command line using the argument {@code -gui} for + * actual use. + */ + public static void main(String[] args) throws Exception { + CliContext cliContext = new CliContext(); + String v = Common.getVersion(args); + String definitions = VersionUtilities.packageForVersion(v) + "#" + v; + ValidationEngine validationEngine = Common.getValidationEngine(v, definitions, cliContext.getTxLog()); + start(new CliContext(), validationEngine, false); + } + + public static void start(CliContext currentContext, ValidationEngine validationEngine, boolean bootBrowser) { + app = Javalin.create(); + new RestEndpoints().initRestEndpoints(app, currentContext, validationEngine); + app.config.addStaticFiles(WEB_APP_FILE_LOCATION); + app.start(GUI_FRONTEND_PORT); + if (bootBrowser) { + openBrowser(); + } + } + + public static void openBrowser() { + if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) { + try { + Desktop.getDesktop().browse(new URI(PAGE_ADDRESS)); + } catch (Exception e) { + System.out.println("Error opening web browser to validator GUI.\nYou can try to open the page manually at:: " + + PAGE_ADDRESS + "\nError:: " + e.getMessage()); + } + } + } + + public static void stop() { + app.stop(); + } + +} diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/controller/CliContextController.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/controller/CliContextController.java new file mode 100644 index 000000000..afd3e4478 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/controller/CliContextController.java @@ -0,0 +1,30 @@ +package org.hl7.fhir.validation.cli.controller; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.javalin.http.Context; +import org.apache.http.HttpStatus; +import org.hl7.fhir.validation.cli.model.CliContext; +import org.jetbrains.annotations.NotNull; + +public class CliContextController { + + private final String JSON_MIME_TYPE = "application/json"; + + private CliContext myCliContext; + + public CliContextController(CliContext cliContext) { + this.myCliContext = cliContext; + } + + public void handleGetCurrentCliContext(@NotNull Context ctx) throws JsonProcessingException { + ObjectMapper Obj = new ObjectMapper(); + String jsonStr = Obj.writeValueAsString(myCliContext); + ctx.result(jsonStr).contentType(JSON_MIME_TYPE).status(HttpStatus.SC_OK); + } + + public void handleSetCurrentCliContext(@NotNull Context ctx) { + myCliContext = ctx.bodyAsClass(CliContext.class); + ctx.status(HttpStatus.SC_OK); + } +} diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/controller/UIController.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/controller/UIController.java new file mode 100644 index 000000000..fcb978335 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/controller/UIController.java @@ -0,0 +1,13 @@ +package org.hl7.fhir.validation.cli.controller; + +import io.javalin.http.Handler; + +public class UIController { + + public UIController() {} + + public Handler renderLandingPage = ctx -> { + ctx.render("/public/index.html"); + }; + +} diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/controller/ValidationController.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/controller/ValidationController.java new file mode 100644 index 000000000..48af31ccd --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/controller/ValidationController.java @@ -0,0 +1,38 @@ +package org.hl7.fhir.validation.cli.controller; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.javalin.http.Context; +import io.javalin.http.Handler; +import org.apache.http.HttpStatus; +import org.hl7.fhir.validation.ValidationEngine; +import org.hl7.fhir.validation.cli.model.ValidationRequest; +import org.hl7.fhir.validation.cli.model.ValidationResponse; +import org.hl7.fhir.validation.cli.services.ValidationService; + +public class ValidationController { + + private ValidationEngine myValidationEngine; + + public ValidationController(ValidationEngine validationEngine) { + this.myValidationEngine = validationEngine; + } + + public void handleValidationRequest(Context ctx) { + ValidationRequest request = ctx.bodyAsClass(ValidationRequest.class); + ValidationResponse response = null; + try { + response = ValidationService.validateSources(request, myValidationEngine); + ObjectMapper Obj = new ObjectMapper(); + /* + * TODO + * Write file contents to temp files to pass to validator instead of creating our own endpoint. + * Create File => new temp file + * Use Option => DeleteOnShutdown + */ + String jsonStr = Obj.writeValueAsString(response); + ctx.status(200).json(jsonStr); + } catch (Exception e) { + ctx.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).result(e.getLocalizedMessage()); + } + } +} diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/CliContext.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/model/CliContext.java similarity index 68% rename from org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/CliContext.java rename to org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/model/CliContext.java index 13146ee8c..951628ffa 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/CliContext.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/model/CliContext.java @@ -1,6 +1,8 @@ -package org.hl7.fhir.validation.cli; +package org.hl7.fhir.validation.cli.model; +import com.fasterxml.jackson.annotation.JsonProperty; import org.hl7.fhir.validation.Validator; +import org.hl7.fhir.validation.cli.utils.SnomedVersion; import java.util.*; @@ -9,46 +11,82 @@ 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"; + @JsonProperty("doNative") private boolean doNative = false; + @JsonProperty("anyExtensionsAllowed") private boolean anyExtensionsAllowed = true; + @JsonProperty("hintAboutNonMustSupport") private boolean hintAboutNonMustSupport = false; + @JsonProperty("recursive") 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 = SnomedVersion.INTL.getCode(); - private String targetVer = null; + @JsonProperty("doDebug") private boolean doDebug = false; - private boolean noInternalCaching = false; // internal, for when debugging terminology validation - private boolean noExtensibleBindingMessages = false; + @JsonProperty("assumeValidRestReferences") private boolean assumeValidRestReferences = false; + @JsonProperty("canDoNative") + private boolean canDoNative = false; + @JsonProperty("noInternalCaching") + private boolean noInternalCaching = false; // internal, for when debugging terminology validation + @JsonProperty("noExtensibleBindingMessages") + private boolean noExtensibleBindingMessages = false; + @JsonProperty("map") + private String map = null; + @JsonProperty("output") + private String output = null; + @JsonProperty("txServer") + private String txServer = "http://tx.fhir.org"; + @JsonProperty("sv") + private String sv = "current"; + @JsonProperty("txLog") + private String txLog = null; + @JsonProperty("mapLog") + private String mapLog = null; + @JsonProperty("lang") + private String lang = null; + @JsonProperty("fhirpath") + private String fhirpath = null; + @JsonProperty("snomedCT") + private String snomedCT = SnomedVersion.INTL.getCode(); + @JsonProperty("targetVer") + private String targetVer = null; + + @JsonProperty("igs") + private List igs = new ArrayList(); + @JsonProperty("questionnaires") + private List questionnaires = new ArrayList(); + @JsonProperty("profiles") + private List profiles = new ArrayList(); + @JsonProperty("sources") + private List sources = new ArrayList(); + + @JsonProperty("mode") + private Validator.EngineMode mode = Validator.EngineMode.VALIDATION; + + @JsonProperty("locale") + private String locale = Locale.ENGLISH.getDisplayLanguage(); + + @JsonProperty("locations") + private Map locations = new HashMap(); + + + @JsonProperty("map") public String getMap() { return map; } + @JsonProperty("map") public CliContext setMap(String map) { this.map = map; return this; } + @JsonProperty("igs") public List getIgs() { return igs; } + @JsonProperty("igs") public CliContext setIgs(List igs) { this.igs = igs; return this; @@ -62,10 +100,12 @@ public class CliContext { return this; } + @JsonProperty("questionnaires") public List getQuestionnaires() { return questionnaires; } + @JsonProperty("questionnaires") public CliContext setQuestionnaires(List questionnaires) { this.questionnaires = questionnaires; return this; @@ -79,64 +119,87 @@ public class CliContext { return this; } + @JsonProperty("txServer") public String getTxServer() { return txServer; } + @JsonProperty("txServer") public CliContext setTxServer(String txServer) { this.txServer = txServer; return this; } + @JsonProperty("doNative") public boolean isDoNative() { return doNative; } + @JsonProperty("doNative") public CliContext setDoNative(boolean doNative) { this.doNative = doNative; return this; } + @JsonProperty("anyExtensionsAllowed") public boolean isAnyExtensionsAllowed() { return anyExtensionsAllowed; } + @JsonProperty("anyExtensionsAllowed") public CliContext setAnyExtensionsAllowed(boolean anyExtensionsAllowed) { this.anyExtensionsAllowed = anyExtensionsAllowed; return this; } + @JsonProperty("hintAboutNonMustSupport") public boolean isHintAboutNonMustSupport() { return hintAboutNonMustSupport; } + @JsonProperty("hintAboutNonMustSupport") public CliContext setHintAboutNonMustSupport(boolean hintAboutNonMustSupport) { this.hintAboutNonMustSupport = hintAboutNonMustSupport; return this; } + @JsonProperty("recursive") public boolean isRecursive() { return recursive; } + @JsonProperty("recursive") public CliContext setRecursive(boolean recursive) { this.recursive = recursive; return this; } - public Locale getLocale() { + @JsonProperty("locale") + public String getLanguageCode() { return locale; } - public CliContext setLocale(Locale locale) { - this.locale = locale; + public Locale getLocale() { + return Locale.forLanguageTag(this.locale); + } + + @JsonProperty("locale") + public CliContext setLocale(String languageString) { + this.locale = languageString; return this; } + public CliContext setLocale(Locale locale) { + this.locale = locale.getDisplayLanguage(); + return this; + } + + @JsonProperty("profiles") public List getProfiles() { return profiles; } + @JsonProperty("profiles") public CliContext setProfiles(List profiles) { this.profiles = profiles; return this; @@ -150,37 +213,45 @@ public class CliContext { return this; } + @JsonProperty("mode") public Validator.EngineMode getMode() { return mode; } + @JsonProperty("mode") public CliContext setMode(Validator.EngineMode mode) { this.mode = mode; return this; } + @JsonProperty("output") public String getOutput() { return output; } + @JsonProperty("output") public CliContext setOutput(String output) { this.output = output; return this; } - public Boolean getCanDoNative() { + @JsonProperty("canDoNative") + public boolean getCanDoNative() { return canDoNative; } - public CliContext setCanDoNative(Boolean canDoNative) { + @JsonProperty("canDoNative") + public CliContext setCanDoNative(boolean canDoNative) { this.canDoNative = canDoNative; return this; } + @JsonProperty("sources") public List getSources() { return sources; } + @JsonProperty("sources") public CliContext setSources(List sources) { this.sources = sources; return this; @@ -194,10 +265,12 @@ public class CliContext { return this; } + @JsonProperty("locations") public Map getLocations() { return locations; } + @JsonProperty("locations") public CliContext setLocations(Map locations) { this.locations = locations; return this; @@ -208,104 +281,129 @@ public class CliContext { return this; } + @JsonProperty("sv") public String getSv() { return sv; } + @JsonProperty("sv") public CliContext setSv(String sv) { this.sv = sv; return this; } + @JsonProperty("txLog") public String getTxLog() { return txLog; } + @JsonProperty("txLog") public CliContext setTxLog(String txLog) { this.txLog = txLog; return this; } + @JsonProperty("mapLog") public String getMapLog() { return mapLog; } + @JsonProperty("mapLog") public CliContext setMapLog(String mapLog) { this.mapLog = mapLog; return this; } + @JsonProperty("lang") public String getLang() { return lang; } + @JsonProperty("lang") public CliContext setLang(String lang) { this.lang = lang; return this; } + @JsonProperty("fhirpath") public String getFhirpath() { return fhirpath; } + @JsonProperty("fhirpath") public CliContext setFhirpath(String fhirpath) { this.fhirpath = fhirpath; return this; } - public String getSnomedCT() { + public SnomedVersion getSnomedCT() { + return SnomedVersion.getFromCode(snomedCT); + } + + @JsonProperty("snomedCT") + public String getSnomedCTCode() { return snomedCT; } + @JsonProperty("snomedCT") public CliContext setSnomedCT(String snomedCT) { - this.snomedCT = SnomedVersion.resolveSnomedCTCode(snomedCT); + this.snomedCT = snomedCT; return this; } + @JsonProperty("targetVer") public String getTargetVer() { return targetVer; } + @JsonProperty("targetVer") public CliContext setTargetVer(String targetVer) { this.targetVer = targetVer; return this; } + @JsonProperty("doDebug") public boolean isDoDebug() { return doDebug; } + @JsonProperty("doDebug") public CliContext setDoDebug(boolean doDebug) { this.doDebug = doDebug; return this; } + @JsonProperty("assumeValidRestReferences") public boolean isAssumeValidRestReferences() { return assumeValidRestReferences; } + @JsonProperty("assumeValidRestReferences") public CliContext setAssumeValidRestReferences(boolean assumeValidRestReferences) { this.assumeValidRestReferences = assumeValidRestReferences; return this; } + @JsonProperty("noInternalCaching") public boolean isNoInternalCaching() { return noInternalCaching; } + @JsonProperty("noInternalCaching") public CliContext setNoInternalCaching(boolean noInternalCaching) { this.noInternalCaching = noInternalCaching; return this; } + @JsonProperty("noExtensibleBindingMessages") public boolean isNoExtensibleBindingMessages() { return noExtensibleBindingMessages; } + @JsonProperty("noExtensibleBindingMessages") public CliContext setNoExtensibleBindingMessages(boolean noExtensibleBindingMessages) { this.noExtensibleBindingMessages = noExtensibleBindingMessages; return this; } - } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/model/CliContextTest.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/model/CliContextTest.java new file mode 100644 index 000000000..82466642c --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/model/CliContextTest.java @@ -0,0 +1,80 @@ +package org.hl7.fhir.validation.cli.model; + +/** + * A POJO for storing the flags/values for the CLI validator. + */ +public class CliContextTest { + + private boolean doNative = false; + private boolean anyExtensionsAllowed = true; + private boolean hintAboutNonMustSupport = false; + private boolean recursive = false; + private boolean doDebug = false; + private boolean assumeValidRestReferences = false; + + public boolean isDoNative() { + return doNative; + } + + public CliContextTest setDoNative(boolean doNative) { + this.doNative = doNative; + return this; + } + + public boolean isAnyExtensionsAllowed() { + return anyExtensionsAllowed; + } + + public CliContextTest setAnyExtensionsAllowed(boolean anyExtensionsAllowed) { + this.anyExtensionsAllowed = anyExtensionsAllowed; + return this; + } + + public boolean isHintAboutNonMustSupport() { + return hintAboutNonMustSupport; + } + + public CliContextTest setHintAboutNonMustSupport(boolean hintAboutNonMustSupport) { + this.hintAboutNonMustSupport = hintAboutNonMustSupport; + return this; + } + + public boolean isRecursive() { + return recursive; + } + + public CliContextTest setRecursive(boolean recursive) { + this.recursive = recursive; + return this; + } + + public boolean isDoDebug() { + return doDebug; + } + + public CliContextTest setDoDebug(boolean doDebug) { + this.doDebug = doDebug; + return this; + } + + public boolean isAssumeValidRestReferences() { + return assumeValidRestReferences; + } + + public CliContextTest setAssumeValidRestReferences(boolean assumeValidRestReferences) { + this.assumeValidRestReferences = assumeValidRestReferences; + return this; + } + + @Override + public String toString() { + return "CliContext{" + + ", doNative=" + doNative + + ", anyExtensionsAllowed=" + anyExtensionsAllowed + + ", hintAboutNonMustSupport=" + hintAboutNonMustSupport + + ", recursive=" + recursive + + ", doDebug=" + doDebug + + ", assumeValidRestReferences=" + assumeValidRestReferences + + '}'; + } +} diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/model/FileInfo.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/model/FileInfo.java new file mode 100644 index 000000000..7a6999b14 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/model/FileInfo.java @@ -0,0 +1,49 @@ +package org.hl7.fhir.validation.cli.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.hl7.fhir.r5.elementmodel.Manager; + +public class FileInfo { + + @JsonProperty("fileName") + private String fileName; + + @JsonProperty("fileContent") + private String fileContent; + + @JsonProperty("fileType") + private String fileType; + + @JsonProperty("fileName") + public String getFileName() { + return fileName; + } + + @JsonProperty("fileName") + public FileInfo setFileName(String fileName) { + this.fileName = fileName; + return this; + } + + @JsonProperty("fileContent") + public String getFileContent() { + return fileContent; + } + + @JsonProperty("fileContent") + public FileInfo setFileContent(String fileContent) { + this.fileContent = fileContent; + return this; + } + + @JsonProperty("fileType") + public Manager.FhirFormat getFileType() { + return Manager.FhirFormat.JSON; + } + + @JsonProperty("fileType") + public FileInfo setFileType(String fileType) { + this.fileType = fileType; + return this; + } +} diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/model/ValidationIssue.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/model/ValidationIssue.java new file mode 100644 index 000000000..a18f1a33e --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/model/ValidationIssue.java @@ -0,0 +1,32 @@ +package org.hl7.fhir.validation.cli.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class ValidationIssue { + @JsonProperty("severity") + private String severity; + @JsonProperty("details") + private String details; + + @JsonProperty("severity") + public String getSeverity() { + return severity; + } + + @JsonProperty("severity") + public ValidationIssue setSeverity(String severity) { + this.severity = severity; + return this; + } + + @JsonProperty("details") + public String getDetails() { + return details; + } + + @JsonProperty("details") + public ValidationIssue setDetails(String details) { + this.details = details; + return this; + } +} diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/model/ValidationOutcome.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/model/ValidationOutcome.java new file mode 100644 index 000000000..1510c806b --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/model/ValidationOutcome.java @@ -0,0 +1,47 @@ +package org.hl7.fhir.validation.cli.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.hl7.fhir.r5.model.OperationOutcome; + +import java.util.ArrayList; +import java.util.List; + +public class ValidationOutcome { + + @JsonProperty("fileInfo") + private FileInfo fileInfo; + @JsonProperty("issues") + private List issues = new ArrayList<>(); + + @JsonProperty("fileInfo") + public FileInfo getFileInfo() { + return fileInfo; + } + + @JsonProperty("fileInfo") + public ValidationOutcome setFileInfo(FileInfo fileInfo) { + this.fileInfo = fileInfo; + return this; + } + + @JsonProperty("issues") + public List getIssues() { + return issues; + } + + @JsonProperty("issues") + public ValidationOutcome setIssues(List issues) { + this.issues = issues; + return this; + } + + public ValidationOutcome addIssue(OperationOutcome.OperationOutcomeIssueComponent outcome) { + String text = outcome.getDetails().getText(); + text.replace("\'", "\""); + issues.add(new ValidationIssue() + .setSeverity(outcome.getSeverity().getDisplay()) + .setDetails(outcome.getDetails().getText())); + return this; + } + +} diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/model/ValidationRequest.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/model/ValidationRequest.java new file mode 100644 index 000000000..a515c5afa --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/model/ValidationRequest.java @@ -0,0 +1,45 @@ +package org.hl7.fhir.validation.cli.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.ArrayList; +import java.util.List; + +public class ValidationRequest { + + @JsonProperty("cliContext") + private CliContext cliContext; + + @JsonProperty("filesToValidate") + private List filesToValidate = new ArrayList<>(); + + @JsonProperty("cliContext") + public CliContext getCliContext() { + return cliContext; + } + + @JsonProperty("cliContext") + public ValidationRequest setCliContext(CliContext cliContext) { + this.cliContext = cliContext; + return this; + } + + @JsonProperty("filesToValidate") + public List getFilesToValidate() { + return filesToValidate; + } + + @JsonProperty("filesToValidate") + public ValidationRequest setFilesToValidate(List filesToValidate) { + this.filesToValidate = filesToValidate; + return this; + } + + public String listSourceFiles() { + List fileNames = new ArrayList<>(); + for (FileInfo fp : filesToValidate) { + fileNames.add(fp.getFileName()); + } + return String.join(", ", fileNames); + } +} diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/model/ValidationResponse.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/model/ValidationResponse.java new file mode 100644 index 000000000..7c010916d --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/model/ValidationResponse.java @@ -0,0 +1,33 @@ +package org.hl7.fhir.validation.cli.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.ArrayList; +import java.util.List; + +public class ValidationResponse { + + @JsonProperty("outcomes") + public List outcomes = new ArrayList<>(); + + @JsonProperty("outcomes") + public List getOutcomes() { + return outcomes; + } + + @JsonProperty("outcomes") + public ValidationResponse setOutcomes(List outcomes) { + this.outcomes = outcomes; + return this; + } + + public ValidationResponse addOutcome(ValidationOutcome outcome) { + if (outcomes == null) { + outcomes = new ArrayList<>(); + } + outcomes.add(outcome); + return this; + } + +} + diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/Comparison.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/ComparisonService.java similarity index 91% rename from org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/Comparison.java rename to org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/ComparisonService.java index 2ae398529..5e584d339 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/Comparison.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/ComparisonService.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.validation.cli; +package org.hl7.fhir.validation.cli.services; import org.hl7.fhir.r5.conformance.CapabilityStatementUtilities; import org.hl7.fhir.r5.conformance.ProfileComparer; @@ -14,6 +14,7 @@ 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 org.hl7.fhir.validation.cli.utils.Params; import java.awt.*; import java.io.File; @@ -21,7 +22,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.util.UUID; -public class Comparison { +public class ComparisonService { public static void doLeftRightComparison(String[] args, String dest, ValidationEngine validator) throws IOException { // ok now set up the comparison @@ -39,9 +40,9 @@ public class Comparison { if (resLeft != null && resRight != null) { if (resLeft instanceof StructureDefinition && resRight instanceof StructureDefinition) { - Comparison.compareStructureDefinitions(dest, validator, left, right, (StructureDefinition) resLeft, (StructureDefinition) resRight); + ComparisonService.compareStructureDefinitions(dest, validator, left, right, (StructureDefinition) resLeft, (StructureDefinition) resRight); } else if (resLeft instanceof CapabilityStatement && resRight instanceof CapabilityStatement) { - Comparison.compareCapabilityStatements(args, dest, validator, left, right, (CanonicalResource) resLeft, (CanonicalResource) resRight); + ComparisonService.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() + ")"); } @@ -71,7 +72,7 @@ public class Comparison { 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"); + String destHtml = Utilities.path(dest, "public/index.html"); File htmlFile = new File(destHtml); Desktop.getDesktop().browse(htmlFile.toURI()); System.out.println("Done"); diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/ValidationUtils.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/ValidationService.java similarity index 88% rename from org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/ValidationUtils.java rename to org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/ValidationService.java index eee487e8c..6aacedbb6 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/ValidationUtils.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/ValidationService.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.validation.cli; +package org.hl7.fhir.validation.cli.services; import org.hl7.fhir.r5.context.TerminologyCache; import org.hl7.fhir.r5.elementmodel.Manager; @@ -10,6 +10,7 @@ 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 org.hl7.fhir.validation.cli.model.*; import java.io.File; import java.io.FileOutputStream; @@ -17,13 +18,37 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -public class ValidationUtils { +public class ValidationService { + + public static ValidationResponse validateSources(ValidationRequest request, ValidationEngine validator) throws Exception { + if (request.getCliContext().getProfiles().size() > 0) { + System.out.println(" .. validate " + request.listSourceFiles() + " against " + request.getCliContext().getProfiles().toString()); + } else { + System.out.println(" .. validate " + request.listSourceFiles()); + } + validator.prepare(); // generate any missing snapshots + + ValidationResponse response = new ValidationResponse(); + for (FileInfo fp : request.getFilesToValidate()) { + OperationOutcome operationOutcome = validator.validate(fp.getFileContent().getBytes(), fp.getFileType(), + request.getCliContext().getProfiles()); + ValidationOutcome outcome = new ValidationOutcome(); + + // Need to set file content to null as server can't handle json in json + fp.setFileContent(null); + outcome.setFileInfo(fp); + operationOutcome.getIssue().forEach(outcome::addIssue); + response.addOutcome(outcome); + } + return response; + } public static void validateSources(CliContext cliContext, ValidationEngine validator) throws Exception { - if (cliContext.getProfiles().size() > 0) + if (cliContext.getProfiles().size() > 0) { System.out.println(" .. validate " + cliContext.getSources() + " against " + cliContext.getProfiles().toString()); - else + } else { System.out.println(" .. validate " + cliContext.getSources()); + } validator.prepare(); // generate any missing snapshots Resource r = validator.validate(cliContext.getSources(), cliContext.getProfiles()); int ec = 0; @@ -154,7 +179,7 @@ public class ValidationUtils { validator.setAnyExtensionsAllowed(cliContext.isAnyExtensionsAllowed()); validator.setLanguage(cliContext.getLang()); validator.setLocale(cliContext.getLocale()); - validator.setSnomedExtension(cliContext.getSnomedCT()); + validator.setSnomedExtension(cliContext.getSnomedCTCode()); validator.setAssumeValidRestReferences(cliContext.isAssumeValidRestReferences()); validator.setNoExtensibleBindingMessages(cliContext.isNoExtensibleBindingMessages()); TerminologyCache.setNoCaching(cliContext.isNoInternalCaching()); diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/Common.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/Common.java similarity index 88% rename from org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/Common.java rename to org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/Common.java index 66e617399..f13de0b4e 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/Common.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/Common.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.validation.cli; +package org.hl7.fhir.validation.cli.utils; import org.hl7.fhir.r5.model.Constants; import org.hl7.fhir.r5.model.FhirPublication; @@ -75,11 +75,9 @@ public class Common { } } - public static ValidationEngine getValidationEngine(String[] args, String txLog) throws Exception { - 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); + public static ValidationEngine getValidationEngine(String version, String definitions, String txLog) throws Exception { + System.out.println("Loading (v = " + version + ", tx server http://tx.fhir.org)"); + return new ValidationEngine(definitions, "http://tx.fhir.org", txLog, FhirPublication.fromCode(version), version); } } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/Display.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/Display.java similarity index 99% rename from org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/Display.java rename to org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/Display.java index 4bfda8ecc..f06fe27cf 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/Display.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/Display.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.validation.cli; +package org.hl7.fhir.validation.cli.utils; import org.hl7.fhir.r5.model.Constants; import org.hl7.fhir.utilities.VersionUtilities; diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/Params.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/Params.java similarity index 98% rename from org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/Params.java rename to org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/Params.java index 115b51397..ee465e372 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/Params.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/Params.java @@ -1,7 +1,8 @@ -package org.hl7.fhir.validation.cli; +package org.hl7.fhir.validation.cli.utils; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.validation.Validator; +import org.hl7.fhir.validation.cli.model.CliContext; import java.io.File; import java.util.Arrays; @@ -9,6 +10,7 @@ import java.util.Locale; public class Params { + public static final String GUI = "-gui"; public static final String VERSION = "-version"; public static final String OUTPUT = "-output"; public static final String PROXY = "-proxy"; diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/SnomedVersion.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/SnomedVersion.java similarity index 65% rename from org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/SnomedVersion.java rename to org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/SnomedVersion.java index 84a33a65e..3be055e5f 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/SnomedVersion.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/SnomedVersion.java @@ -1,6 +1,8 @@ -package org.hl7.fhir.validation.cli; +package org.hl7.fhir.validation.cli.utils; import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; import java.util.Optional; public enum SnomedVersion { @@ -32,15 +34,15 @@ public enum SnomedVersion { return 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"); + public static SnomedVersion getFromCode(String code) { + return lookup.get(code); + } + + private static final Map lookup = new HashMap<>(); + + static { + for (SnomedVersion s : SnomedVersion.values()) { + lookup.put(s.getCode(), s); } } } diff --git a/org.hl7.fhir.validation/src/main/resources/public/assets/fhir-logo-www.png b/org.hl7.fhir.validation/src/main/resources/public/assets/fhir-logo-www.png new file mode 100644 index 000000000..90cb7dc81 Binary files /dev/null and b/org.hl7.fhir.validation/src/main/resources/public/assets/fhir-logo-www.png differ diff --git a/org.hl7.fhir.validation/src/main/resources/public/assets/json-svgrepo-com.svg b/org.hl7.fhir.validation/src/main/resources/public/assets/json-svgrepo-com.svg new file mode 100644 index 000000000..5643327d1 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/resources/public/assets/json-svgrepo-com.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.hl7.fhir.validation/src/main/resources/public/assets/xml-svgrepo-com.svg b/org.hl7.fhir.validation/src/main/resources/public/assets/xml-svgrepo-com.svg new file mode 100644 index 000000000..d0b7a4375 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/resources/public/assets/xml-svgrepo-com.svg @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.hl7.fhir.validation/src/main/resources/public/cliwindow.html b/org.hl7.fhir.validation/src/main/resources/public/cliwindow.html new file mode 100644 index 000000000..607f775e6 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/resources/public/cliwindow.html @@ -0,0 +1,56 @@ + diff --git a/org.hl7.fhir.validation/src/main/resources/public/enums/EngineMode.js b/org.hl7.fhir.validation/src/main/resources/public/enums/EngineMode.js new file mode 100644 index 000000000..63b88cdec --- /dev/null +++ b/org.hl7.fhir.validation/src/main/resources/public/enums/EngineMode.js @@ -0,0 +1,10 @@ +export const EngineMode { + VALIDATION, + TRANSFORM, + NARRATIVE, + SNAPSHOT, + SCAN, + CONVERT, + FHIRPATH, + VERSION +} diff --git a/org.hl7.fhir.validation/src/main/resources/public/enums/FhirFormat.js b/org.hl7.fhir.validation/src/main/resources/public/enums/FhirFormat.js new file mode 100644 index 000000000..c7df35004 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/resources/public/enums/FhirFormat.js @@ -0,0 +1,17 @@ +export const FhirFormat = { + XML: { + extension:'xml' + }, + JSON: { + extension:'json' + }, + TURTLE: { + extension:'ttl' + }, + TEXT: { + extension:'txt' + }, + VBAR: { + extension:'hl7' + }, +} diff --git a/org.hl7.fhir.validation/src/main/resources/public/enums/IssueSeverity.js b/org.hl7.fhir.validation/src/main/resources/public/enums/IssueSeverity.js new file mode 100644 index 000000000..89665077f --- /dev/null +++ b/org.hl7.fhir.validation/src/main/resources/public/enums/IssueSeverity.js @@ -0,0 +1,14 @@ +export const IssueSeverity = { + FATAL: { + code: 'Fatal' + }, + ERROR: { + code: 'Error' + }, + WARNING: { + code: 'Warning' + }, + INFORMATION: { + code: 'Information' + } +} diff --git a/org.hl7.fhir.validation/src/main/resources/public/enums/Locale.js b/org.hl7.fhir.validation/src/main/resources/public/enums/Locale.js new file mode 100644 index 000000000..e3195a1d8 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/resources/public/enums/Locale.js @@ -0,0 +1,30 @@ +export const Locale = { + ENGLISH: { + code: 'en', + value: 'English' + }, + FRENCH: { + code: 'fr', + value: 'French' + }, + GERMAN: { + code: 'de', + value: 'German' + }, + ITALIAN: { + code: 'it', + value: 'Italian' + }, + JAPANESE: { + code: 'ja', + value: 'Japanese' + }, + KOREAN: { + code: 'ko', + value: 'Korean' + }, + CHINESE: { + code: 'zh', + value: 'Chinese' + } +} diff --git a/org.hl7.fhir.validation/src/main/resources/public/enums/SnomedVersion.js b/org.hl7.fhir.validation/src/main/resources/public/enums/SnomedVersion.js new file mode 100644 index 000000000..3f82d797f --- /dev/null +++ b/org.hl7.fhir.validation/src/main/resources/public/enums/SnomedVersion.js @@ -0,0 +1,38 @@ +export const SnomedVersion = { + INTL: { + value: "intl", + code: "900000000000207008" + }, + US: { + value: "us", + code: "731000124108" + }, + UK: { + value: "uk", + code: "999000041000000102" + }, + AU: { + value: "au", + code: "32506021000036107" + }, + CA: { + value: "ca", + code: "20611000087101" + }, + NL: { + value: "nl", + code: "11000146104" + }, + SE: { + value: "se", + code: "45991000052106" + }, + ES: { + value: "es", + code: "449081005" + }, + DK: { + value: "dk", + code: "554471000005108" + } +} diff --git a/org.hl7.fhir.validation/src/main/resources/public/index.html b/org.hl7.fhir.validation/src/main/resources/public/index.html new file mode 100644 index 000000000..e698edd74 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/resources/public/index.html @@ -0,0 +1,99 @@ + + + + + + + FHIR HL7 Resrouce Validator GUI + + + + + + + + + + + + + + + + + + FHIR Core Validator + Experimental + + + + + + Files to Validate + Validate + + + + + + + + + + + Add Files + + + + + + + + + + + + Collapsible Group Item #1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.hl7.fhir.validation/src/main/resources/public/main.js b/org.hl7.fhir.validation/src/main/resources/public/main.js new file mode 100644 index 000000000..76ddbc1d1 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/resources/public/main.js @@ -0,0 +1,206 @@ +import {CliContext} from './model/CliContext.js'; +import {ValidationRequest} from './model/ValidationRequest.js'; +import {FileInfo} from './model/FileInfo.js'; +import {FhirFormat} from './enums/FhirFormat.js'; +import {IssueSeverity} from './enums/IssueSeverity.js'; + +/* + +*/ + +// Icon Constants +const jsonIcon = './assets/json-svgrepo-com.svg'; +const xmlIcon = './assets/xml-svgrepo-com.svg'; + +// HTML classes +const CLASS_LIST_ITEM_PLAIN = "list-group-item"; +const CLASS_LIST_ITEM_FATAL = "list-group-item list-group-item-dark"; +const CLASS_LIST_ITEM_ERROR = "list-group-item list-group-item-danger"; +const CLASS_LIST_ITEM_WARNING = "list-group-item list-group-item-warning"; +const CLASS_LIST_ITEM_INFORMATION = "list-group-item list-group-item-info"; + +// HTML IDs +const ID_FILE_ENTRY_TEMPLATE = '#file_entry_template'; +const ID_FILE_ENTRY_NAME = 'file_entry_name_field'; +const ID_FILE_ENTRY_ICON = 'file_entry_type_icon'; +const ID_FILE_ENTRY_DELETE_BUTTON = 'file_entry_delete_button'; +const ID_FILE_ENTRY_FILE_LIST = 'file_entry_file_list'; +const ID_FILE_ENTRY_OUTCOME_LIST = 'file_entry_outcome_list'; +const ID_FILE_ENTRY_COLLAPSE_SECTION = 'file_entry_collapse_section'; + +/* + +*/ + +// Data Fields +const cli = new CliContext(); +const filesToValidate = []; + +document.getElementById('validate_button').addEventListener("click", validateCurrentFiles); +document.getElementById('files').addEventListener('change', handleFileSelect, false); + +// File reading +function handleFileSelect(evt) { + var files = evt.target.files; + var output = []; + for (var i = 0, f; f = files[i]; i++) { + generateFileEntry(f); + // Check for proper file type here + console.log(f.type); + } +} + +function generateFileEntry(file) { + var fr = new FileReader(); + fr.onload = function(e) { + // TODO there may be timing issues here + filesToValidate.push(new FileInfo(file.name, e.target.result, file.type)); + document.getElementById(ID_FILE_ENTRY_FILE_LIST).appendChild(generateNewFileListItemFromTemplate(file, filesToValidate.length - 1)); + }; + fr.readAsText(file); +} + +// File List Template Generation + +function generateNewFileListItemFromTemplate(file, index) { + var template = document.querySelector(ID_FILE_ENTRY_TEMPLATE); + var clone = template.content.cloneNode(true); + + // Add file name + clone.getElementById(ID_FILE_ENTRY_NAME).textContent = file.name; + + // Add appropriate icon for filetype + if (file.type.includes(FhirFormat.JSON.extension)) { + clone.getElementById(ID_FILE_ENTRY_ICON).src = jsonIcon; + } else if (file.type.includes(FhirFormat.XML.extension)) { + clone.getElementById(ID_FILE_ENTRY_ICON).src = xmlIcon; + } + + clone.getElementById(ID_FILE_ENTRY_COLLAPSE_SECTION).setAttribute("id", (ID_FILE_ENTRY_COLLAPSE_SECTION + index)); + clone.getElementById(ID_FILE_ENTRY_NAME).setAttribute("aria-controls", (ID_FILE_ENTRY_COLLAPSE_SECTION + index)); + clone.getElementById(ID_FILE_ENTRY_NAME).setAttribute("data-target", ('#' + ID_FILE_ENTRY_COLLAPSE_SECTION + index)); + + // Add delete listener + clone.getElementById(ID_FILE_ENTRY_DELETE_BUTTON).addEventListener("click", handleDeleteOnFileList); + + return clone; +} + +function addIssueToFileEntryList(index, severity, details) { + var ul = document.getElementById(ID_FILE_ENTRY_FILE_LIST); + var listItems = ul.children; + var fileEntry = listItems[index]; + console.log(fileEntry); + var listOfIssues = fileEntry.querySelector('#' + ID_FILE_ENTRY_OUTCOME_LIST); + var issueItem = createIssueListItem(severity, details); + listOfIssues.appendChild(issueItem); +} + +function createIssueListItem(severity, details) { + var newIssue = document.createElement('li'); + switch(severity) { + case IssueSeverity.FATAL.code: + newIssue.setAttribute("class", CLASS_LIST_ITEM_FATAL); + break; + case IssueSeverity.ERROR.code: + newIssue.setAttribute("class", CLASS_LIST_ITEM_ERROR); + break; + case IssueSeverity.WARNING.code: + newIssue.setAttribute("class", CLASS_LIST_ITEM_WARNING); + break; + case IssueSeverity.INFORMATION.code: + newIssue.setAttribute("class", CLASS_LIST_ITEM_INFORMATION); + break; + default: + console.error('Passed in bad severity: ' + severity); + } + newIssue.innerHTML = details; + return newIssue; +} + +function handleDeleteOnFileList(e) { + var li = e.target.closest('li'); + var nodes = Array.from( li.closest('ul').children ); + var index = nodes.indexOf( li ); + nodes[index].remove(); + filesToValidate.splice((index - 1), 1); + console.log('Index -> ' + index); + console.log(filesToValidate); +} + +// Validation +function validateCurrentFiles() { + sendFilesToValidate(filesToValidate); +} + +function sendFilesToValidate(arrayOfFileInfo) { + var req = new ValidationRequest(); + req.filesToValidate = arrayOfFileInfo; + + var xhr = new XMLHttpRequest(); + xhr.open("POST", 'http://localhost:8080/' + 'validate', true); + xhr.setRequestHeader('Content-Type', 'application/json'); + xhr.send(JSON.stringify(req)); + + xhr.onload = function () { + const response = '{"outcomes": [{"fileInfo": {"fileName": "account-example.canonical.json", "fileType": "JSON"}, "issues": [{"severity": "Error", "details": "\"null\""}, {"severity": "Error", "details": "Profile http://hl7.org/fhir/StructureDefinition/Account, Element: minimum required = 1, but only found 0"}]}, {"fileInfo": {"fileName": "account-example(example).xml", "fileType": "XML"}, "issues": []}]}'; + var test = xhr.responseText; + processValidationResponse(JSON.parse(JSON.parse(xhr.responseText))); + }; +} + +function processValidationResponse(validationResponse) { + console.log(validationResponse); + console.log(validationResponse.length); + console.log(validationResponse.outcomes); + console.log(validationResponse.outcomes.length); + + for (var i = 0; i < validationResponse.outcomes.length; i++) { + console.log(validationResponse.outcomes[i]); + var fileInfo = validationResponse.outcomes[i].fileInfo; + var issues = validationResponse.outcomes[i].issues; + issues.forEach(issue => { + console.log(issue); + addIssueToFileEntryList(i, issue.severity, issue.details); + }); + } + +} + + + + +// window.onload = function loadCliContext() { +// var xhr = new XMLHttpRequest(); +// xhr.open("GET", 'http://localhost:8080/currentContext'); +// xhr.send(); +// xhr.onreadystatechange = function() { +// if (this.readyState == 4 && this.status == 200) { +// console.log(xhr.responseText); +// } +// } +// } + +// /* +// Escape JSON +// */ +// var escapeJSON = exports.escapeJSON = function(json) { +// var escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; +// var meta = { // table of character substitutions +// '\b': '\\b', +// '\t': '\\t', +// '\n': '\\n', +// '\f': '\\f', +// '\r': '\\r', +// '"' : '\\"', +// '\\': '\\\\' +// }; +// +// escapable.lastIndex = 0; +// return escapable.test(json) ? '"' + json.replace(escapable, function (a) { +// var c = meta[a]; +// return (typeof c === 'string') ? c +// : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); +// }) + '"' : '"' + json + '"'; +// +// }; diff --git a/org.hl7.fhir.validation/src/main/resources/public/model/CliContext.js b/org.hl7.fhir.validation/src/main/resources/public/model/CliContext.js new file mode 100644 index 000000000..673637cd9 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/resources/public/model/CliContext.js @@ -0,0 +1,34 @@ +import {SnomedVersion} from '../enums/SnomedVersion.js'; +import {Locale} from '../enums/Locale.js'; + +export class CliContext { + constructor(){ + this.doNative = false; + this.anyExtensionsAllowed = true; + this.hintAboutNonMustSupport = false; + this.recursive = false; + this.doDebug = false; + this.assumeValidRestReferences = false; + this.canDoNative = false; + + this.map = null; + this.output = null; + this.txServer = "http://tx.fhir.org"; + this.sv = "current"; + this.txLog = null; + this.mapLog = null; + this.lang = null; + this.fhirpath = null; + this.snomedCT = SnomedVersion.ES.value; + this.targetVer = null; + + this.igs = []; + this.questionnaires = []; + this.profiles = []; + this.sources = []; + + this.locale = Locale.ENGLISH.value; + + this.locations = new Map(); + } +} diff --git a/org.hl7.fhir.validation/src/main/resources/public/model/FileInfo.js b/org.hl7.fhir.validation/src/main/resources/public/model/FileInfo.js new file mode 100644 index 000000000..d853c1e44 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/resources/public/model/FileInfo.js @@ -0,0 +1,13 @@ +import {FhirFormat} from '../enums/FhirFormat.js'; + +export class FileInfo { + constructor(fileName, fileContent, type){ + this.fileName = fileName; + this.fileContent = fileContent; + if (type.includes('json')) { + this.fileType = FhirFormat.JSON.extension; + } else if (type.includes('xml')) { + this.fileType = FhirFormat.XML.extension; + } + } +} diff --git a/org.hl7.fhir.validation/src/main/resources/public/model/ValidationIssue.js b/org.hl7.fhir.validation/src/main/resources/public/model/ValidationIssue.js new file mode 100644 index 000000000..0ce182359 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/resources/public/model/ValidationIssue.js @@ -0,0 +1,6 @@ +export class ValidationIssue { + constructor(){ + this.severity = ""; + this.details = ""; + } +} diff --git a/org.hl7.fhir.validation/src/main/resources/public/model/ValidationOutcome.js b/org.hl7.fhir.validation/src/main/resources/public/model/ValidationOutcome.js new file mode 100644 index 000000000..77f5e41d0 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/resources/public/model/ValidationOutcome.js @@ -0,0 +1,8 @@ +import {FileInfo} from './FileInfo.js'; + +export class ValidationOutcome { + constructor(){ + this.fileInfo = null; + this.issues = []; + } +} diff --git a/org.hl7.fhir.validation/src/main/resources/public/model/ValidationRequest.js b/org.hl7.fhir.validation/src/main/resources/public/model/ValidationRequest.js new file mode 100644 index 000000000..85b7559bb --- /dev/null +++ b/org.hl7.fhir.validation/src/main/resources/public/model/ValidationRequest.js @@ -0,0 +1,8 @@ +import {CliContext} from './CliContext.js'; + +export class ValidationRequest { + constructor(){ + this.cliContext = new CliContext(); + this.filesToValidate = []; + } +} diff --git a/org.hl7.fhir.validation/src/main/resources/public/model/ValidationResponse.js b/org.hl7.fhir.validation/src/main/resources/public/model/ValidationResponse.js new file mode 100644 index 000000000..d128d3e30 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/resources/public/model/ValidationResponse.js @@ -0,0 +1,7 @@ +import {ValidationOutcome} from './ValidationOutcome.js'; + +export class ValidationResponse { + constructor() { + this.outcomes = []; + } +} diff --git a/org.hl7.fhir.validation/src/main/resources/public/style.css b/org.hl7.fhir.validation/src/main/resources/public/style.css new file mode 100644 index 000000000..1cba70413 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/resources/public/style.css @@ -0,0 +1,94 @@ +/* */ +.container{ + width:80%; + margin:auto; + overflow: hidden; +} + +#main{ + float: left; + width: 70%; +} + +#sidebar{ + float: right; + width: 30%; +} + + +html, +body { + overflow-x: hidden; /* Prevent scroll on narrow devices */ +} + +body { + padding-top: 56px; +} + +@media (max-width: 991.98px) { + .offcanvas-collapse { + position: fixed; + top: 56px; /* Height of navbar */ + bottom: 0; + left: 100%; + width: 100%; + padding-right: 1rem; + padding-left: 1rem; + overflow-y: auto; + visibility: hidden; + background-color: #343a40; + transition: visibility .3s ease-in-out, -webkit-transform .3s ease-in-out; + transition: transform .3s ease-in-out, visibility .3s ease-in-out; + transition: transform .3s ease-in-out, visibility .3s ease-in-out, -webkit-transform .3s ease-in-out; + } + .offcanvas-collapse.open { + visibility: visible; + -webkit-transform: translateX(-100%); + transform: translateX(-100%); + } +} + +.nav-scroller { + position: relative; + z-index: 2; + height: 2.75rem; + overflow-y: hidden; +} + +.nav-scroller .nav { + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; + padding-bottom: 1rem; + margin-top: -1px; + overflow-x: auto; + color: rgba(255, 255, 255, .75); + text-align: center; + white-space: nowrap; + -webkit-overflow-scrolling: touch; +} + +.nav-underline .nav-link { + padding-top: .75rem; + padding-bottom: .75rem; + font-size: .875rem; + color: #6c757d; +} + +.nav-underline .nav-link:hover { + color: #007bff; +} + +.nav-underline .active { + font-weight: 500; + color: #343a40; +} + +.text-white-50 { color: rgba(255, 255, 255, .5); } + +.bg-purple { background-color: #6f42c1; } + +.lh-100 { line-height: 1; } +.lh-125 { line-height: 1.25; } +.lh-150 { line-height: 1.5; } diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/cli/BaseRestTest.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/cli/BaseRestTest.java new file mode 100644 index 000000000..cd3a88874 --- /dev/null +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/cli/BaseRestTest.java @@ -0,0 +1,36 @@ +package org.hl7.fhir.validation.cli; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.http.HttpResponse; +import org.apache.http.util.EntityUtils; +import org.hl7.fhir.validation.cli.model.CliContext; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; + +import java.io.IOException; + +public abstract class BaseRestTest { + + protected final String JSON_MIME_TYPE = "application/json"; + + @BeforeAll + public static void startServer() { + ValidatorGui.start(new CliContext(), null, false); + } + + @AfterAll + public static void stopServer() { + ValidatorGui.stop(); + } + + public static T retrieveResourceFromResponse(HttpResponse response, Class clazz) + throws IOException { + + String jsonFromResponse = EntityUtils.toString(response.getEntity()); + ObjectMapper mapper = new ObjectMapper() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + return mapper.readValue(jsonFromResponse, clazz); + } + +} diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/cli/ValidatorGuiTest.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/cli/ValidatorGuiTest.java new file mode 100644 index 000000000..b8e88e779 --- /dev/null +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/cli/ValidatorGuiTest.java @@ -0,0 +1,33 @@ +package org.hl7.fhir.validation.cli; + +import io.github.bonigarcia.wdm.WebDriverManager; +import org.hl7.fhir.validation.cli.model.CliContext; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.chrome.ChromeDriver; +import org.openqa.selenium.chrome.ChromeOptions; + +import java.io.IOException; + +class ValidatorGuiTest { + + private final String HTML_TITLE_TAG = "FHIR HL7 Resrouce Validator GUI"; + + @Test + @DisplayName("Page boots correctly, and displays index.html") + public void UI_contains_correct_heading() throws IOException { + ValidatorGui.start(new CliContext(), null, false); + WebDriverManager.chromedriver().setup(); + ChromeOptions options = new ChromeOptions(); + options.addArguments("--headless"); + options.addArguments("--disable-gpu"); + WebDriver driver = new ChromeDriver(options); + driver.get("http://localhost:8080/home"); + + Assertions.assertTrue(driver.getPageSource().contains(HTML_TITLE_TAG)); + driver.quit(); + ValidatorGui.stop(); + } +} \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/cli/controller/HttpGetContextTest.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/cli/controller/HttpGetContextTest.java new file mode 100644 index 000000000..ac10cd47a --- /dev/null +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/cli/controller/HttpGetContextTest.java @@ -0,0 +1,47 @@ +package org.hl7.fhir.validation.cli.controller; + +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.entity.ContentType; +import org.apache.http.impl.client.HttpClientBuilder; +import org.hl7.fhir.validation.cli.BaseRestTest; +import org.hl7.fhir.validation.cli.model.CliContext; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +class HttpGetContextTest extends BaseRestTest { + + private final String GET_CONTEXT_URL = "http://localhost:8080/context"; + + @Test + @DisplayName("Testing status code on get context endpoint.") + public void testStatus() throws IOException { + HttpUriRequest request = new HttpGet(GET_CONTEXT_URL); + HttpResponse httpResponse = HttpClientBuilder.create().build().execute(request); + Assertions.assertEquals(httpResponse.getStatusLine().getStatusCode(), HttpStatus.SC_OK); + } + + @Test + @DisplayName("Testing media type on get context endpoint.") + public void testMediaType() throws IOException { + HttpUriRequest request = new HttpGet(GET_CONTEXT_URL); + HttpResponse httpResponse = HttpClientBuilder.create().build().execute(request); + String mimeType = ContentType.getOrDefault(httpResponse.getEntity()).getMimeType(); + Assertions.assertEquals(JSON_MIME_TYPE, mimeType ); + } + + @Test + @DisplayName("Testing status code on get context endpoint.") + public void testJSONPayload() throws IOException { + HttpUriRequest request = new HttpGet(GET_CONTEXT_URL); + HttpResponse httpResponse = HttpClientBuilder.create().build().execute(request); + CliContext resource = retrieveResourceFromResponse(httpResponse, CliContext.class); + Assertions.assertEquals(new CliContext(), resource); + } + +} \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/cli/controller/HttpPutContextTest.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/cli/controller/HttpPutContextTest.java new file mode 100644 index 000000000..5c967191e --- /dev/null +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/cli/controller/HttpPutContextTest.java @@ -0,0 +1,24 @@ +package org.hl7.fhir.validation.cli.controller; + +import io.javalin.http.Context; + +import org.junit.jupiter.api.Test; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +class HttpPutContextTest { + + public CliContextController myCliContextController; + + public HttpPutContextTest() { + this.myCliContextController = new CliContextController(null); + } + + @Test + void handleSetCurrentCliContext() { + Context context = mock(Context.class); + this.myCliContextController.handleSetCurrentCliContext(context); + verify(context).status(200); + } +} \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/org.hl7.fhir.validation/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker new file mode 100644 index 000000000..ca6ee9cea --- /dev/null +++ b/org.hl7.fhir.validation/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker @@ -0,0 +1 @@ +mock-maker-inline \ No newline at end of file