diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/TerminologyClientR2.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/TerminologyClientR2.java index 82e468d56..5a0e23cc2 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/TerminologyClientR2.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/TerminologyClientR2.java @@ -26,7 +26,7 @@ import java.util.Map; import org.hl7.fhir.dstu2.utils.client.FHIRToolingClient; import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.r5.context.HTMLClientLogger; +import org.hl7.fhir.r5.utils.client.ToolingClientLogger; import org.hl7.fhir.r5.model.CapabilityStatement; import org.hl7.fhir.r5.model.Parameters; import org.hl7.fhir.r5.model.TerminologyCapabilities; @@ -81,7 +81,7 @@ public class TerminologyClientR2 implements TerminologyClient { } @Override - public void setLogger(HTMLClientLogger txLog) { + public void setLogger(ToolingClientLogger txLog) { // ignored in this version - need to roll R4 internal changes back to R2 if desired } diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/TerminologyClientR3.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/TerminologyClientR3.java index eac4201a1..ede3958d5 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/TerminologyClientR3.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/TerminologyClientR3.java @@ -26,7 +26,7 @@ import java.util.Map; import org.hl7.fhir.dstu3.utils.client.FHIRToolingClient; import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.r5.context.HTMLClientLogger; +import org.hl7.fhir.r5.utils.client.ToolingClientLogger; import org.hl7.fhir.r5.model.CapabilityStatement; import org.hl7.fhir.r5.model.Parameters; import org.hl7.fhir.r5.model.TerminologyCapabilities; @@ -79,7 +79,7 @@ public class TerminologyClientR3 implements TerminologyClient { } @Override - public void setLogger(HTMLClientLogger txLog) { + public void setLogger(ToolingClientLogger txLog) { // ignored in this version - need to roll R4 internal changes back to R2 if desired } diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/TerminologyClientR4.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/TerminologyClientR4.java index 5cdc46c82..726903fe4 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/TerminologyClientR4.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/TerminologyClientR4.java @@ -26,7 +26,7 @@ import java.util.Map; import org.hl7.fhir.r4.utils.client.FHIRToolingClient; import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.r5.context.HTMLClientLogger; +import org.hl7.fhir.r5.utils.client.ToolingClientLogger; import org.hl7.fhir.r5.model.CapabilityStatement; import org.hl7.fhir.r5.model.Parameters; import org.hl7.fhir.r5.model.TerminologyCapabilities; @@ -79,7 +79,7 @@ public class TerminologyClientR4 implements TerminologyClient { } @Override - public void setLogger(HTMLClientLogger txLog) { + public void setLogger(ToolingClientLogger txLog) { // ignored in this version - need to roll R4 internal changes back to R2 if desired } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java index 8d366c15c..c3d374a87 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java @@ -79,12 +79,14 @@ import org.hl7.fhir.r5.terminologies.ValueSetExpander.TerminologyServiceErrorCla import org.hl7.fhir.r5.terminologies.ValueSetExpander.ValueSetExpansionOutcome; import org.hl7.fhir.r5.terminologies.ValueSetExpanderSimple; import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.r5.utils.client.ToolingClientLogger; import org.hl7.fhir.utilities.OIDUtils; import org.hl7.fhir.utilities.TerminologyServiceOptions; import org.hl7.fhir.utilities.TranslationServices; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.validation.ValidationOptions; +import org.hl7.fhir.utilities.validation.ValidationOptions.ValueSetMode; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; @@ -148,7 +150,7 @@ public abstract class BaseWorkerContext implements IWorkerContext { private boolean allowLoadingDuplicates; protected TerminologyClient txClient; - protected HTMLClientLogger txLog; + protected ToolingClientLogger txLog; private TerminologyCapabilities txcaps; private boolean canRunWithoutTerminology; protected boolean noTerminologyServer; @@ -593,8 +595,12 @@ public abstract class BaseWorkerContext implements IWorkerContext { } private void setTerminologyOptions(ValidationOptions options, Parameters pIn) { - if (!Utilities.noString(options.getLanguage())) + if (!Utilities.noString(options.getLanguage())) { pIn.addParameter("displayLanguage", options.getLanguage()); + } + if (options.getValueSetMode() != ValueSetMode.ALL_CHECKS) { + pIn.addParameter("valueSetMode", options.getValueSetMode().toString()); + } } @Override diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java index 8bb64989a..48b52336f 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java @@ -241,7 +241,11 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon try { tlog("Connect to "+client.getAddress()); txClient = client; - txLog = new HTMLClientLogger(log); + if (log != null && log.endsWith(".txt")) { + txLog = new TextClientLogger(log); + } else { + txLog = new HTMLClientLogger(log); + } txClient.setLogger(txLog); return txClient.getCapabilitiesStatementQuick().getSoftware().getVersion(); } catch (Exception e) { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/TextClientLogger.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/TextClientLogger.java new file mode 100644 index 000000000..7f1503c06 --- /dev/null +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/TextClientLogger.java @@ -0,0 +1,92 @@ +package org.hl7.fhir.r5.context; + +/*- + * #%L + * org.hl7.fhir.r5 + * %% + * Copyright (C) 2014 - 2019 Health Level 7 + * %% + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + + +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; +import java.util.List; + +import org.hl7.fhir.r5.utils.client.ToolingClientLogger; +import org.hl7.fhir.utilities.Utilities; + +public class TextClientLogger implements ToolingClientLogger { + + private PrintStream file; + private int id = 0; + private String lastId; + + public TextClientLogger(String log) { + if (log != null) { + try { + file = new PrintStream(new FileOutputStream(log)); + } catch (FileNotFoundException e) { + } + } + } + + @Override + public void logRequest(String method, String url, List headers, byte[] body) { + if (file == null) + return; + id++; + lastId = Integer.toString(id); + file.println("\r\n--- "+lastId+" -----------------\r\nRequest: \r\n"); + file.println(method+" "+url+" HTTP/1.0"); + for (String s : headers) + file.println(Utilities.escapeXml(s)); + if (body != null) { + file.println(""); + try { + file.println(Utilities.escapeXml(new String(body, "UTF-8"))); + } catch (UnsupportedEncodingException e) { + } + } + } + + @Override + public void logResponse(String outcome, List headers, byte[] body) { + if (file == null) + return; + file.println("\r\n\r\nResponse: \r\n"); + file.println(outcome); + for (String s : headers) + file.println(Utilities.escapeXml(s)); + if (body != null) { + file.println(""); + try { + file.println(Utilities.escapeXml(new String(body, "UTF-8"))); + } catch (UnsupportedEncodingException e) { + } + } + } + + public String getLastId() { + return lastId; + } + + public void clearLastId() { + lastId = null; + } + +} diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/TerminologyClient.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/TerminologyClient.java index be5fb18b1..2206e24f6 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/TerminologyClient.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/TerminologyClient.java @@ -29,6 +29,7 @@ import org.hl7.fhir.r5.model.CapabilityStatement; import org.hl7.fhir.r5.model.Parameters; import org.hl7.fhir.r5.model.TerminologyCapabilities; import org.hl7.fhir.r5.model.ValueSet; +import org.hl7.fhir.r5.utils.client.ToolingClientLogger; public interface TerminologyClient { public String getAddress(); @@ -37,7 +38,7 @@ public interface TerminologyClient { public Parameters validateCS(Parameters pin) throws FHIRException; public Parameters validateVS(Parameters pin) throws FHIRException; public void setTimeout(int i) throws FHIRException; - public void setLogger(HTMLClientLogger txLog) throws FHIRException; + public void setLogger(ToolingClientLogger txLog) throws FHIRException; public CapabilityStatement getCapabilitiesStatementQuick() throws FHIRException; public Parameters lookupCode(Map params) throws FHIRException; } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/TerminologyClientR5.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/TerminologyClientR5.java index 0990b1fbf..179878bea 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/TerminologyClientR5.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/TerminologyClientR5.java @@ -31,6 +31,7 @@ import org.hl7.fhir.r5.model.Parameters; import org.hl7.fhir.r5.model.TerminologyCapabilities; import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.utils.client.FHIRToolingClient; +import org.hl7.fhir.r5.utils.client.ToolingClientLogger; public class TerminologyClientR5 implements TerminologyClient { @@ -71,7 +72,7 @@ public class TerminologyClientR5 implements TerminologyClient { } @Override - public void setLogger(HTMLClientLogger txLog) { + public void setLogger(ToolingClientLogger txLog) { client.setLogger(txLog); } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java index 6d6bbef43..bca063a1d 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java @@ -48,6 +48,7 @@ import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.TerminologyServiceOptions; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.validation.ValidationOptions; +import org.hl7.fhir.utilities.validation.ValidationOptions.ValueSetMode; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; public class ValueSetCheckerSimple implements ValueSetChecker { @@ -67,22 +68,24 @@ public class ValueSetCheckerSimple implements ValueSetChecker { // first, we validate the codings themselves List errors = new ArrayList(); List warnings = new ArrayList(); - for (Coding c : code.getCoding()) { - if (!c.hasSystem()) - warnings.add("Coding has no system - cannot validate"); - CodeSystem cs = context.fetchCodeSystem(c.getSystem()); - ValidationResult res = null; - if (cs == null || cs.getContent() != CodeSystemContentMode.COMPLETE) { - res = context.validateCode(options.noClient(), c, null); - } else { - res = validateCode(c, cs); + if (options.getValueSetMode() != ValueSetMode.CHECK_MEMERSHIP_ONLY) { + for (Coding c : code.getCoding()) { + if (!c.hasSystem()) + warnings.add("Coding has no system - cannot validate"); + CodeSystem cs = context.fetchCodeSystem(c.getSystem()); + ValidationResult res = null; + if (cs == null || cs.getContent() != CodeSystemContentMode.COMPLETE) { + res = context.validateCode(options.noClient(), c, null); + } else { + res = validateCode(c, cs); + } + if (!res.isOk()) + errors.add(res.getMessage()); + else if (res.getMessage() != null) + warnings.add(res.getMessage()); } - if (!res.isOk()) - errors.add(res.getMessage()); - else if (res.getMessage() != null) - warnings.add(res.getMessage()); } - if (valueset != null) { + if (valueset != null && options.getValueSetMode() != ValueSetMode.NO_MEMBERSHIP_CHECK) { boolean ok = false; for (Coding c : code.getCoding()) { ok = ok || codeInValueSet(c.getSystem(), c.getCode()); @@ -101,38 +104,45 @@ public class ValueSetCheckerSimple implements ValueSetChecker { public ValidationResult validateCode(Coding code) throws FHIRException { String warningMessage = null; // first, we validate the concept itself - - String system = code.hasSystem() ? code.getSystem() : getValueSetSystem(); - if (system == null && !code.hasDisplay()) { // dealing with just a plain code (enum) - system = systemForCodeInValueSet(code.getCode()); - } - if (!code.hasSystem()) - code.setSystem(system); - boolean inExpansion = checkExpansion(code); - CodeSystem cs = context.fetchCodeSystem(system); - if (cs == null) { - warningMessage = "Unable to resolve system "+system+" - system is not specified or implicit"; - if (!inExpansion) - throw new FHIRException(warningMessage); - } - if (cs!=null && cs.getContent() != CodeSystemContentMode.COMPLETE) { - warningMessage = "Unable to resolve system "+system+" - system is not complete"; - if (!inExpansion) - throw new FHIRException(warningMessage); - } - + ValidationResult res =null; - if (cs!=null) - res = validateCode(code, cs); - + boolean inExpansion = false; + String system = code.hasSystem() ? code.getSystem() : getValueSetSystem(); + if (options.getValueSetMode() != ValueSetMode.CHECK_MEMERSHIP_ONLY) { + if (system == null && !code.hasDisplay()) { // dealing with just a plain code (enum) + system = systemForCodeInValueSet(code.getCode()); + } + if (!code.hasSystem()) + code.setSystem(system); + inExpansion = checkExpansion(code); + CodeSystem cs = context.fetchCodeSystem(system); + if (cs == null) { + warningMessage = "Unable to resolve system "+system+" - system is not specified or implicit"; + if (!inExpansion) + throw new FHIRException(warningMessage); + } + if (cs!=null && cs.getContent() != CodeSystemContentMode.COMPLETE) { + warningMessage = "Unable to resolve system "+system+" - system is not complete"; + if (!inExpansion) + throw new FHIRException(warningMessage); + } + + if (cs!=null) + res = validateCode(code, cs); + } else { + inExpansion = checkExpansion(code); + } + // then, if we have a value set, we check it's in the value set - if ((res==null || res.isOk()) && valueset != null && !codeInValueSet(system, code.getCode())) { - if (!inExpansion) - res.setMessage("Not in value set "+valueset.getUrl()).setSeverity(IssueSeverity.ERROR); - else if (warningMessage!=null) - res = new ValidationResult(IssueSeverity.WARNING, "Code found in expansion, however: " + warningMessage); - else - res.setMessage("Code found in expansion, however: " + res.getMessage()); + if (valueset != null && options.getValueSetMode() != ValueSetMode.NO_MEMBERSHIP_CHECK) { + if ((res==null || res.isOk()) && !codeInValueSet(system, code.getCode())) { + if (!inExpansion) + res.setMessage("Not in value set "+valueset.getUrl()).setSeverity(IssueSeverity.ERROR); + else if (warningMessage!=null) + res = new ValidationResult(IssueSeverity.WARNING, "Code found in expansion, however: " + warningMessage); + else + res.setMessage("Code found in expansion, however: " + res.getMessage()); + } } return res; } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/client/ToolingClientLogger.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/client/ToolingClientLogger.java index 67d192e44..8cf699f8f 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/client/ToolingClientLogger.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/client/ToolingClientLogger.java @@ -27,4 +27,8 @@ public interface ToolingClientLogger { public void logRequest(String method, String url, List headers, byte[] body); public void logResponse(String outcome, List headers, byte[] body); + public String getLastId(); + public void clearLastId(); + + } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/validation/ValidationOptions.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/validation/ValidationOptions.java index af0282ede..8924c030f 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/validation/ValidationOptions.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/validation/ValidationOptions.java @@ -1,10 +1,16 @@ package org.hl7.fhir.utilities.validation; + public class ValidationOptions { + public enum ValueSetMode { + ALL_CHECKS, CHECK_MEMERSHIP_ONLY, NO_MEMBERSHIP_CHECK + } + private String language; private boolean useServer = true; private boolean useClient = true; private boolean guessSystem = false; + private ValueSetMode valueSetMode = ValueSetMode.ALL_CHECKS; public ValidationOptions() { super(); @@ -67,10 +73,28 @@ public class ValidationOptions { public String toJson() { - return "\"lang\":\""+language+"\", \"useServer\":\""+Boolean.toString(useServer)+"\", \"useClient\":\""+Boolean.toString(useClient)+"\", \"guessSystem\":\""+Boolean.toString(guessSystem)+"\""; + return "\"lang\":\""+language+"\", \"useServer\":\""+Boolean.toString(useServer)+"\", \"useClient\":\""+Boolean.toString(useClient)+"\", \"guessSystem\":\""+Boolean.toString(guessSystem)+"\", \"valueSetMode\":\""+valueSetMode.toString()+"\""; } public static ValidationOptions defaults() { return new ValidationOptions("en-US"); } + + public ValidationOptions checkValueSetOnly() { + ValidationOptions n = this.copy(); + n.valueSetMode = ValueSetMode.CHECK_MEMERSHIP_ONLY; + return n; + } + + public ValidationOptions noCheckValueSetMembership() { + ValidationOptions n = this.copy(); + n.valueSetMode = ValueSetMode.NO_MEMBERSHIP_CHECK; + return n; + } + + public ValueSetMode getValueSetMode() { + return valueSetMode; + } + + } \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/r5/validation/InstanceValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/r5/validation/InstanceValidator.java index 37c2f4e30..9eff5ddb0 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/r5/validation/InstanceValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/r5/validation/InstanceValidator.java @@ -530,7 +530,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } public void addAncestorProfiles(StructureDefinition sd) { - if (sd.hasDerivation() && sd.getDerivation().equals(StructureDefinition.TypeDerivationRule.CONSTRAINT)) { + if (sd.hasDerivation() && sd.getDerivation() == StructureDefinition.TypeDerivationRule.CONSTRAINT) { StructureDefinition parentSd = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition()); if (parentSd != null && !profiles.containsKey(parentSd)) { ProfileUsage pu = new ProfileUsage(parentSd); @@ -944,7 +944,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return true; // we don't validate these else { CodeSystem cs = getCodeSystem(system); - if (rule(errors, IssueType.CODEINVALID, element.line(), element.col(), path, cs != null, "Unknown Code System " + system)) { + if (rule(errors, IssueType.CODEINVALID, element.line(), element.col(), path, cs != null, "Unknown Code System '" + system+"'")) { ConceptDefinitionComponent def = getCodeDefinition(cs, code); if (warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, def != null, "Unknown Code (" + system + "#" + code + ")")) return warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, display == null || display.equals(def.getDisplay()), "Display should be '" + def.getDisplay() + "'"); @@ -962,6 +962,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat rule(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, "Invalid System URI: "+system+" - cannot use a value set URI as a system"); // Lloyd: This error used to prohibit checking for downstream issues, but there are some cases where that checking needs to occur. Please talk to me before changing the code back. } + hint(errors, IssueType.UNKNOWN, element.line(), element.col(), path, false, "Code System URI '"+system+"' is unknown so the code cannot be validated"); return true; } catch (Exception e) { @@ -1076,7 +1077,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (!atLeastOneSystemIsSupported && binding.getStrength() == BindingStrength.EXAMPLE) { // ignore this since we can't validate but it doesn't matter.. } else { - ValidationResult vr = context.validateCode(new ValidationOptions(stack.workingLang), cc, valueset); // we're going to validate the codings directly + ValidationResult vr = context.validateCode(new ValidationOptions(stack.workingLang).checkValueSetOnly(), cc, valueset); // we're going to validate the codings directly, so only check the valueset if (!vr.isOk()) { bindingsOk = false; if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure()) { @@ -1112,12 +1113,16 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat // to validate, we'll validate that the codes actually exist if (bindingsOk) { for (Coding nextCoding : cc.getCoding()) { - String nextCode = nextCoding.getCode(); - String nextSystem = nextCoding.getSystem(); - if (isNotBlank(nextCode) && isNotBlank(nextSystem) && context.supportsSystem(nextSystem)) { - ValidationResult vr = context.validateCode(new ValidationOptions(stack.workingLang), nextSystem, nextCode, null); - if (!vr.isOk()) { - txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, "Code {0} is not a valid code in code system {1}", nextCode, nextSystem); + if (isNotBlank(nextCoding.getCode()) && isNotBlank(nextCoding.getSystem()) && context.supportsSystem(nextCoding.getSystem())) { + ValidationResult vr = context.validateCode(new ValidationOptions(stack.workingLang).noCheckValueSetMembership(), nextCoding, valueset); + if (vr.getSeverity() != null) { + if (vr.getSeverity() == IssueSeverity.INFORMATION) { + txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, vr.getMessage()); + } else if (vr.getSeverity() == IssueSeverity.WARNING) { + txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, vr.getMessage()); + } else { + txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, vr.getMessage()); + } } } } @@ -4335,9 +4340,6 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L Element resource, Element element, String actualType, NodeStack stack, boolean inCodeableConcept, boolean checkDisplayInContext, String extensionUrl) throws FHIRException, FHIRException, IOException { // element.markValidation(profile, definition); - if (debug) { - System.out.println(" "+stack.getLiteralPath()); - } // time = System.nanoTime(); // check type invariants checkInvariants(hostContext, errors, profile, definition, resource, element, stack, false); @@ -4376,6 +4378,7 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L public void checkChild(ValidatorHostContext hostContext, List errors, StructureDefinition profile, ElementDefinition definition, Element resource, Element element, String actualType, NodeStack stack, boolean inCodeableConcept, boolean checkDisplayInContext, ElementInfo ei, String extensionUrl) throws FHIRException, IOException, DefinitionException { + List profiles = new ArrayList(); if (ei.definition != null) { String type = null; @@ -4446,6 +4449,9 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L } } NodeStack localStack = stack.push(ei.element, ei.count, ei.definition, type == null ? typeDefn : resolveType(type, ei.definition.getType())); + if (debug) { + System.out.println(" "+localStack.getLiteralPath()); + } String localStackLiterapPath = localStack.getLiteralPath(); String eiPath = ei.path; assert(eiPath.equals(localStackLiterapPath)) : "ei.path: " + ei.path + " - localStack.getLiteralPath: " + localStackLiterapPath; diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/r5/validation/Validator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/r5/validation/Validator.java index 81b973d73..bf4c3d31f 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/r5/validation/Validator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/r5/validation/Validator.java @@ -276,6 +276,11 @@ public class Validator { 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"; @@ -314,7 +319,7 @@ public class Validator { } 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", null, FhirPublication.fromCode(v)); + ValidationEngine validator = new ValidationEngine(definitions, "http://tx.fhir.org", txLog, FhirPublication.fromCode(v)); for (int i = 0; i < args.length; i++) { if ("-ig".equals(args[i])) { if (i+1 == args.length) 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 2e89a68e3..c1643caec 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 @@ -129,7 +129,7 @@ public class ValidationEngineTests { int h = hints(op); Assert.assertTrue(e == 1); Assert.assertTrue(w == 0); - Assert.assertTrue(h == 0); + Assert.assertTrue(h == 1); if (!TestUtilities.silent) System.out.println(" .. done: "+Integer.toString(e)+" errors, "+Integer.toString(w)+" warnings, "+Integer.toString(h)+" information messages"); } diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTestSuite.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTestSuite.java index ceb2108d5..6b12bf74c 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTestSuite.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTestSuite.java @@ -93,23 +93,28 @@ public class ValidationTestSuite implements IEvaluationContext, IValidatorResour @Test public void test() throws Exception { System.out.println("Name: " + name+" - base"); + String txLog = null; + if (content.has("txLog")) { + txLog = content.get("txLog").getAsString(); + } String v = "5.0"; List messages = new ArrayList(); - if (content.has("version")) + if (content.has("version")) { v = content.get("version").getAsString(); + } v = VersionUtilities.getMajMin(v); if (!ve.containsKey(v)) { if (v.startsWith("5.0")) - ve.put(v, new ValidationEngine("hl7.fhir.r5.core#current", DEF_TX, null, FhirPublication.R5, true)); + ve.put(v, new ValidationEngine("hl7.fhir.r5.core#current", DEF_TX, txLog, FhirPublication.R5, true)); else if (v.startsWith("3.0")) - ve.put(v, new ValidationEngine("hl7.fhir.r3.core#3.0.2", DEF_TX, null, FhirPublication.STU3, true)); + ve.put(v, new ValidationEngine("hl7.fhir.r3.core#3.0.2", DEF_TX, txLog, FhirPublication.STU3, true)); else if (v.startsWith("4.0")) - ve.put(v, new ValidationEngine("hl7.fhir.r4.core#4.0.1", DEF_TX, null, FhirPublication.R4, true)); + ve.put(v, new ValidationEngine("hl7.fhir.r4.core#4.0.1", DEF_TX, txLog, FhirPublication.R4, true)); else if (v.startsWith("1.0")) - ve.put(v, new ValidationEngine("hl7.fhir.r2.core#1.0.2", DEF_TX, null, FhirPublication.DSTU2, true)); + ve.put(v, new ValidationEngine("hl7.fhir.r2.core#1.0.2", DEF_TX, txLog, FhirPublication.DSTU2, true)); else if (v.startsWith("1.4")) - ve.put(v, new ValidationEngine("hl7.fhir.r2b.core#1.4.0", DEF_TX, null, FhirPublication.DSTU2016May, true)); + ve.put(v, new ValidationEngine("hl7.fhir.r2b.core#1.4.0", DEF_TX, txLog, FhirPublication.DSTU2016May, true)); else throw new Exception("unknown version "+v); } @@ -155,6 +160,11 @@ public class ValidationTestSuite implements IEvaluationContext, IValidatorResour } } List errors = new ArrayList(); + if (content.getAsJsonObject("java").has("debug")) { + val.setDebug(content.getAsJsonObject("java").get("debug").getAsBoolean()); + } else { + val.setDebug(false); + } if (name.endsWith(".json")) val.validate(null, errors, IOUtils.toInputStream(testCaseContent, Charsets.UTF_8), FhirFormat.JSON); else @@ -277,7 +287,7 @@ public class ValidationTestSuite implements IEvaluationContext, IValidatorResour } if (vm.getLevel() == IssueSeverity.INFORMATION) { hc++; - if (java.has("infoCount")) { + if (java.has("infoCount") || java.has("debug")) { System.out.println("hint: "+vm.getDisplay()); } }