Add validator support for -check-references and -resolution-context
This commit is contained in:
parent
99697351a0
commit
8ed34e2604
|
@ -129,6 +129,22 @@ public class ManagedFileAccess {
|
|||
throw new IOException("Internal Error");
|
||||
}
|
||||
}
|
||||
|
||||
public static File file(File root, String filepath) throws IOException {
|
||||
switch (accessPolicy) {
|
||||
case DIRECT:
|
||||
if (!inAllowedPaths(root.getAbsolutePath())) {
|
||||
throw new IOException("The path '"+root.getAbsolutePath()+"' cannot be accessed by policy");
|
||||
}
|
||||
return new File(root.getAbsolutePath(), filepath);
|
||||
case MANAGED:
|
||||
return accessor.file(Utilities.path(root.getAbsolutePath(), filepath));
|
||||
case PROHIBITED:
|
||||
throw new IOException("Access to files is not allowed by local security policy");
|
||||
default:
|
||||
throw new IOException("Internal Error");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Open a FileInputStream, conforming to local security policy
|
||||
**/
|
||||
|
|
|
@ -1184,4 +1184,5 @@ public class I18nConstants {
|
|||
public static final String CODESYSTEM_PROPERTY_BAD_INTERNAL_REFERENCE = "CODESYSTEM_PROPERTY_BAD_INTERNAL_REFERENCE";
|
||||
public static final String CODESYSTEM_PROPERTY_BAD_PROPERTY_CODE = "CODESYSTEM_PROPERTY_BAD_PROPERTY_CODE";
|
||||
public static final String CODESYSTEM_DUPLICATE_CODE = "CODESYSTEM_DUPLICATE_CODE";
|
||||
public static final String REFERENCE_RESOLUTION_FAILED = "REFERENCE_RESOLUTION_FAILED";
|
||||
}
|
||||
|
|
|
@ -343,7 +343,8 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
|||
|
||||
protected boolean slicingHint(List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, boolean thePass, boolean isCritical, String msg, String html, String[] text) {
|
||||
if (!thePass && doingHints()) {
|
||||
addValidationMessage(errors, ruleDate, type, line, col, path, msg, IssueSeverity.INFORMATION, null).setSlicingHint(true).setSliceHtml(html, text).setCriticalSignpost(isCritical);
|
||||
addValidationMessage(errors, ruleDate, type, line, col, path, msg, IssueSeverity.INFORMATION, null)
|
||||
.setMessageId(I18nConstants.DETAILS_FOR__MATCHING_AGAINST_PROFILE_).setSlicingHint(true).setSliceHtml(html, text).setCriticalSignpost(isCritical);
|
||||
}
|
||||
return thePass;
|
||||
}
|
||||
|
@ -356,7 +357,8 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
|||
*/
|
||||
protected boolean slicingHint(List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, boolean thePass, boolean isCritical, String msg, String html, String[] text, List<ValidationMessage> sliceInfo, String id) {
|
||||
if (!thePass && doingHints()) {
|
||||
addValidationMessage(errors, ruleDate, type, line, col, path, msg, IssueSeverity.INFORMATION, id).setSlicingHint(true).setSliceHtml(html, text).setCriticalSignpost(isCritical).setSliceInfo(sliceInfo);
|
||||
addValidationMessage(errors, ruleDate, type, line, col, path, msg, IssueSeverity.INFORMATION, id)
|
||||
.setMessageId(I18nConstants.DETAILS_FOR__MATCHING_AGAINST_PROFILE_).setSlicingHint(true).setSliceHtml(html, text).setCriticalSignpost(isCritical).setSliceInfo(sliceInfo);
|
||||
}
|
||||
return thePass;
|
||||
}
|
||||
|
|
|
@ -35,8 +35,12 @@ import org.hl7.fhir.r5.context.ILoggingService;
|
|||
import org.hl7.fhir.r5.context.IWorkerContextManager;
|
||||
import org.hl7.fhir.r5.context.SimpleWorkerContext;
|
||||
import org.hl7.fhir.r5.context.SystemOutLoggingService;
|
||||
import org.hl7.fhir.r5.elementmodel.*;
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
import org.hl7.fhir.r5.elementmodel.Manager;
|
||||
import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
|
||||
import org.hl7.fhir.r5.elementmodel.ObjectConverter;
|
||||
import org.hl7.fhir.r5.elementmodel.ParserBase;
|
||||
import org.hl7.fhir.r5.elementmodel.SHCParser;
|
||||
import org.hl7.fhir.r5.fhirpath.ExpressionNode;
|
||||
import org.hl7.fhir.r5.fhirpath.FHIRPathEngine;
|
||||
import org.hl7.fhir.r5.formats.FormatUtilities;
|
||||
|
@ -61,9 +65,9 @@ import org.hl7.fhir.r5.model.StructureMap;
|
|||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
import org.hl7.fhir.r5.renderers.RendererFactory;
|
||||
import org.hl7.fhir.r5.renderers.utils.RenderingContext;
|
||||
import org.hl7.fhir.r5.renderers.utils.ResourceWrapper;
|
||||
import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules;
|
||||
import org.hl7.fhir.r5.renderers.utils.RenderingContext.ResourceRendererMode;
|
||||
import org.hl7.fhir.r5.renderers.utils.ResourceWrapper;
|
||||
import org.hl7.fhir.r5.utils.EOperationOutcome;
|
||||
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
||||
import org.hl7.fhir.r5.utils.structuremap.StructureMapUtilities;
|
||||
|
@ -79,6 +83,7 @@ import org.hl7.fhir.r5.utils.validation.constants.CheckDisplayOption;
|
|||
import org.hl7.fhir.r5.utils.validation.constants.ContainedReferenceValidationPolicy;
|
||||
import org.hl7.fhir.r5.utils.validation.constants.IdStatus;
|
||||
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
|
||||
import org.hl7.fhir.utilities.ByteProvider;
|
||||
import org.hl7.fhir.utilities.FhirPublication;
|
||||
import org.hl7.fhir.utilities.IniFile;
|
||||
import org.hl7.fhir.utilities.SIDUtilities;
|
||||
|
@ -107,7 +112,6 @@ import org.hl7.fhir.validation.cli.utils.ValidationLevel;
|
|||
import org.hl7.fhir.validation.instance.InstanceValidator;
|
||||
import org.hl7.fhir.validation.instance.advisor.BasePolicyAdvisorForFullValidation;
|
||||
import org.hl7.fhir.validation.instance.utils.ValidationContext;
|
||||
import org.hl7.fhir.utilities.ByteProvider;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import lombok.Getter;
|
||||
|
|
|
@ -59,6 +59,15 @@ public class CliContext {
|
|||
@SerializedName("assumeValidRestReferences")
|
||||
private
|
||||
boolean assumeValidRestReferences = false;
|
||||
@JsonProperty("checkReferences")
|
||||
@SerializedName("checkReferences")
|
||||
private
|
||||
boolean checkReferences = false;
|
||||
@JsonProperty("resolutionContext")
|
||||
@SerializedName("resolutionContext")
|
||||
private
|
||||
String resolutionContext = null;
|
||||
|
||||
@JsonProperty("canDoNative")
|
||||
@SerializedName("canDoNative")
|
||||
private
|
||||
|
@ -381,6 +390,18 @@ public class CliContext {
|
|||
return this;
|
||||
}
|
||||
|
||||
@SerializedName("resolutionContext")
|
||||
@JsonProperty("resolutionContext")
|
||||
public String getResolutionContext() {
|
||||
return resolutionContext;
|
||||
}
|
||||
|
||||
@SerializedName("resolutionContext")
|
||||
@JsonProperty("resolutionContext")
|
||||
public CliContext setResolutionContext(String resolutionContext) {
|
||||
this.resolutionContext = resolutionContext;
|
||||
return this;
|
||||
}
|
||||
|
||||
@SerializedName("langTransform")
|
||||
@JsonProperty("langTransform")
|
||||
|
@ -967,6 +988,19 @@ public class CliContext {
|
|||
return this;
|
||||
}
|
||||
|
||||
@SerializedName("checkReferences")
|
||||
@JsonProperty("checkReferences")
|
||||
public boolean isCheckReferences() {
|
||||
return checkReferences;
|
||||
}
|
||||
|
||||
@SerializedName("checkReferences")
|
||||
@JsonProperty("checkReferences")
|
||||
public CliContext setCheckReferences(boolean checkReferences) {
|
||||
this.checkReferences = checkReferences;
|
||||
return this;
|
||||
}
|
||||
|
||||
@SerializedName("noInternalCaching")
|
||||
@JsonProperty("noInternalCaching")
|
||||
public boolean isNoInternalCaching() {
|
||||
|
@ -1150,6 +1184,7 @@ public class CliContext {
|
|||
recursive == that.recursive &&
|
||||
doDebug == that.doDebug &&
|
||||
assumeValidRestReferences == that.assumeValidRestReferences &&
|
||||
checkReferences == that.checkReferences &&
|
||||
canDoNative == that.canDoNative &&
|
||||
noInternalCaching == that.noInternalCaching &&
|
||||
noExtensibleBindingMessages == that.noExtensibleBindingMessages &&
|
||||
|
@ -1161,6 +1196,7 @@ public class CliContext {
|
|||
checkIPSCodes == that.checkIPSCodes &&
|
||||
Objects.equals(extensions, that.extensions) &&
|
||||
Objects.equals(map, that.map) &&
|
||||
Objects.equals(resolutionContext, that.resolutionContext) &&
|
||||
Objects.equals(htmlInMarkdownCheck, that.htmlInMarkdownCheck) &&
|
||||
Objects.equals(output, that.output) &&
|
||||
Objects.equals(outputSuffix, that.outputSuffix) &&
|
||||
|
@ -1206,7 +1242,7 @@ public class CliContext {
|
|||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(baseEngine, doNative, extensions, hintAboutNonMustSupport, recursive, doDebug, assumeValidRestReferences, canDoNative, noInternalCaching,
|
||||
return Objects.hash(baseEngine, doNative, extensions, hintAboutNonMustSupport, recursive, doDebug, assumeValidRestReferences, checkReferences,canDoNative, noInternalCaching, resolutionContext,
|
||||
noExtensibleBindingMessages, noInvariants, displayWarnings, wantInvariantsInMessages, map, output, outputSuffix, htmlOutput, txServer, sv, txLog, txCache, mapLog, lang, srcLang, tgtLang, fhirpath, snomedCT,
|
||||
targetVer, packageName, igs, questionnaireMode, level, profiles, options, sources, inputs, mode, locale, locations, crumbTrails, showMessageIds, forPublication, showTimes, allowExampleUrls, outputStyle, jurisdiction, noUnicodeBiDiControlChars,
|
||||
watchMode, watchScanDelay, watchSettleTime, bestPracticeLevel, unknownCodeSystemsCauseErrors, noExperimentalContent, advisorFile, expansionParameters, format, htmlInMarkdownCheck, allowDoubleQuotesInFHIRPath, checkIPSCodes);
|
||||
|
@ -1222,6 +1258,7 @@ public class CliContext {
|
|||
", recursive=" + recursive +
|
||||
", doDebug=" + doDebug +
|
||||
", assumeValidRestReferences=" + assumeValidRestReferences +
|
||||
", checkReferences=" + checkReferences +
|
||||
", canDoNative=" + canDoNative +
|
||||
", noInternalCaching=" + noInternalCaching +
|
||||
", noExtensibleBindingMessages=" + noExtensibleBindingMessages +
|
||||
|
@ -1238,6 +1275,7 @@ public class CliContext {
|
|||
", txLog='" + txLog + '\'' +
|
||||
", txCache='" + txCache + '\'' +
|
||||
", mapLog='" + mapLog + '\'' +
|
||||
", resolutionContext='" + resolutionContext + '\'' +
|
||||
", lang='" + lang + '\'' +
|
||||
", srcLang='" + srcLang + '\'' +
|
||||
", tgtLang='" + tgtLang + '\'' +
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
package org.hl7.fhir.validation.cli.services;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
@ -12,12 +17,18 @@ import java.util.Locale;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.hl7.fhir.convertors.txClient.TerminologyClientFactory;
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||
import org.hl7.fhir.r5.context.IWorkerContext;
|
||||
import org.hl7.fhir.r5.context.IWorkerContextManager;
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
import org.hl7.fhir.r5.elementmodel.Element.SpecialElement;
|
||||
import org.hl7.fhir.r5.elementmodel.Manager;
|
||||
import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
|
||||
import org.hl7.fhir.r5.model.CanonicalResource;
|
||||
import org.hl7.fhir.r5.model.ElementDefinition;
|
||||
import org.hl7.fhir.r5.model.Resource;
|
||||
|
@ -28,17 +39,16 @@ import org.hl7.fhir.r5.utils.validation.IMessagingServices;
|
|||
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
|
||||
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor;
|
||||
import org.hl7.fhir.r5.utils.validation.IValidatorResourceFetcher;
|
||||
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor.AdditionalBindingPurpose;
|
||||
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor.CodedContentValidationAction;
|
||||
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor.ElementValidationAction;
|
||||
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor.ResourceValidationAction;
|
||||
import org.hl7.fhir.r5.utils.validation.constants.BindingKind;
|
||||
import org.hl7.fhir.r5.utils.validation.constants.CodedContentValidationPolicy;
|
||||
import org.hl7.fhir.r5.utils.validation.constants.ContainedReferenceValidationPolicy;
|
||||
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.VersionUtilities;
|
||||
import org.hl7.fhir.utilities.VersionUtilities.VersionURLInfo;
|
||||
import org.hl7.fhir.utilities.filesystem.ManagedFileAccess;
|
||||
import org.hl7.fhir.utilities.http.HTTPResult;
|
||||
import org.hl7.fhir.utilities.http.ManagedWebAccess;
|
||||
import org.hl7.fhir.utilities.json.model.JsonObject;
|
||||
import org.hl7.fhir.utilities.json.parser.JsonParser;
|
||||
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
|
||||
|
@ -47,8 +57,6 @@ import org.hl7.fhir.utilities.validation.ValidationMessage;
|
|||
import org.hl7.fhir.validation.cli.utils.Common;
|
||||
import org.hl7.fhir.validation.instance.advisor.BasePolicyAdvisorForFullValidation;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
|
||||
public class StandAloneValidatorFetcher implements IValidatorResourceFetcher, IValidationPolicyAdvisor, IWorkerContextManager.ICanonicalResourceLocator {
|
||||
|
||||
|
@ -60,6 +68,9 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher, IV
|
|||
private Map<String, String> pidList = new HashMap<>();
|
||||
private Map<String, NpmPackage> pidMap = new HashMap<>();
|
||||
private IValidationPolicyAdvisor policyAdvisor;
|
||||
private String resolutionContext;
|
||||
private Map<String, String> knownFiles = new HashMap<>();
|
||||
|
||||
|
||||
public StandAloneValidatorFetcher(FilesystemPackageCacheManager pcm, IWorkerContext context, IPackageInstaller installer) {
|
||||
this.pcm = pcm;
|
||||
|
@ -69,8 +80,98 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher, IV
|
|||
}
|
||||
|
||||
@Override
|
||||
public Element fetch(IResourceValidator validator, Object appContext, String url) throws FHIRException {
|
||||
throw new FHIRException("The URL '" + url + "' is not known to the FHIR validator, and has not been provided as part of the setup / parameters");
|
||||
public Element fetch(IResourceValidator validator, Object appContext, String url) throws FHIRException, IOException {
|
||||
if (!Utilities.isAbsoluteUrl(url) && Utilities.startsWithInList(resolutionContext, "http:", "https:")) {
|
||||
url = Utilities.pathURL(resolutionContext, url);
|
||||
}
|
||||
|
||||
if (Utilities.isAbsoluteUrl(url)) {
|
||||
HTTPResult cnt = null;
|
||||
try {
|
||||
cnt = ManagedWebAccess.get(Arrays.asList("web"), url, "application/json");
|
||||
cnt.checkThrowException();
|
||||
|
||||
} catch (Exception e) {
|
||||
cnt = ManagedWebAccess.get(Arrays.asList("web"), url, "application/fhir+xml");
|
||||
cnt.checkThrowException();
|
||||
}
|
||||
if (cnt.getContentType() != null && cnt.getContentType().contains("xml")) {
|
||||
return Manager.parse(context, new ByteArrayInputStream(cnt.getContent()), FhirFormat.XML).get(0).getElement();
|
||||
} else {
|
||||
return Manager.parse(context, new ByteArrayInputStream(cnt.getContent()), FhirFormat.JSON).get(0).getElement();
|
||||
}
|
||||
} else if (resolutionContext == null) {
|
||||
throw new FHIRException("The URL '" + url + "' is not known to the FHIR validator, and a resolution context has not been provided as part of the setup / parameters");
|
||||
} else if (resolutionContext.startsWith("file:")) {
|
||||
File rc = ManagedFileAccess.file(resolutionContext.substring(5));
|
||||
if (!rc.exists()) {
|
||||
throw new FHIRException("The URL '" + url + "' is not known to the FHIR validator, and a resolution context has not been provided as part of the setup / parameters");
|
||||
}
|
||||
// first we look for the file by several different patterns
|
||||
File tgt = ManagedFileAccess.file(rc, url);
|
||||
if (tgt.exists()) {
|
||||
return see(tgt, loadFile(tgt));
|
||||
}
|
||||
tgt = ManagedFileAccess.file(rc, url+".json");
|
||||
if (tgt.exists()) {
|
||||
return see(tgt, loadFile(tgt));
|
||||
}
|
||||
tgt = ManagedFileAccess.file(rc, url+".xml");
|
||||
if (tgt.exists()) {
|
||||
return see(tgt, loadFile(tgt));
|
||||
}
|
||||
String[] p = url.split("\\/");
|
||||
if (p.length != 2) {
|
||||
throw new FHIRException("The URL '" + url + "' was not understood - expecting type/id");
|
||||
}
|
||||
if (knownFiles.containsKey(p[0]+"/"+p[1])) {
|
||||
tgt = ManagedFileAccess.file(knownFiles.get(p[0]+"/"+p[1]));
|
||||
return loadFile(tgt);
|
||||
}
|
||||
tgt = ManagedFileAccess.file(rc, p[0]+"-"+p[1]+".json");
|
||||
if (tgt.exists()) {
|
||||
return see(tgt, loadFile(tgt));
|
||||
}
|
||||
tgt = ManagedFileAccess.file(rc, p[0]+"-"+p[1]+".xml");
|
||||
if (tgt.exists()) {
|
||||
return see(tgt, loadFile(tgt));
|
||||
}
|
||||
// didn't find it? now scan...
|
||||
for (File f : ManagedFileAccess.listFiles(rc)) {
|
||||
if (isPossibleMatch(f, p[0], p[1])) {
|
||||
Element e = see(f, loadFile(f));
|
||||
if (p[0].equals(e.fhirType()) && p[1].equals(e.getIdBase())) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
throw new FHIRException("The resolution context '"+resolutionContext+"' was not understood");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private Element see(File f, Element e) {
|
||||
knownFiles.put(e.fhirType()+"/"+e.getIdBase(), f.getAbsolutePath());
|
||||
return e;
|
||||
}
|
||||
|
||||
private boolean isPossibleMatch(File f, String rt, String id) throws FileNotFoundException, IOException {
|
||||
String src = TextFile.fileToString(f);
|
||||
if (f.getName().endsWith(".xml")) {
|
||||
return src.contains("<"+rt) && src.contains("\""+id+"\"");
|
||||
} else {
|
||||
return src.contains("\""+rt+"\"") && src.contains("\""+id+"\"");
|
||||
}
|
||||
}
|
||||
|
||||
private Element loadFile(File tgt) throws FHIRFormatError, DefinitionException, FHIRException, FileNotFoundException, IOException {
|
||||
if (tgt.getName().endsWith(".xml")) {
|
||||
return Manager.parse(context, new FileInputStream(tgt), FhirFormat.XML).get(0).getElement();
|
||||
} else {
|
||||
return Manager.parse(context, new FileInputStream(tgt), FhirFormat.JSON).get(0).getElement();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -78,7 +179,7 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher, IV
|
|||
Object appContext,
|
||||
String path,
|
||||
String url) {
|
||||
return ReferenceValidationPolicy.IGNORE;
|
||||
return policyAdvisor.policyForReference(validator, appContext, path, url);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -344,6 +445,14 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher, IV
|
|||
return policyAdvisor.getReferencePolicy();
|
||||
}
|
||||
|
||||
public void setReferencePolicy(ReferenceValidationPolicy policy) {
|
||||
if (policyAdvisor instanceof BasePolicyAdvisorForFullValidation) {
|
||||
((BasePolicyAdvisorForFullValidation) policyAdvisor).setRefpol(policy);
|
||||
} else {
|
||||
throw new Error("Cannot set reference policy on a "+policy.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
public IValidationPolicyAdvisor getPolicyAdvisor() {
|
||||
return policyAdvisor;
|
||||
}
|
||||
|
@ -353,4 +462,12 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher, IV
|
|||
return this;
|
||||
}
|
||||
|
||||
public String getResolutionContext() {
|
||||
return resolutionContext;
|
||||
}
|
||||
|
||||
public void setResolutionContext(String resolutionContext) {
|
||||
this.resolutionContext = resolutionContext;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -636,6 +636,12 @@ public class ValidationService {
|
|||
validationEngine.setFetcher(fetcher);
|
||||
validationEngine.getContext().setLocator(fetcher);
|
||||
validationEngine.setPolicyAdvisor(fetcher);
|
||||
if (cliContext.isCheckReferences()) {
|
||||
fetcher.setReferencePolicy(ReferenceValidationPolicy.CHECK_VALID);
|
||||
} else {
|
||||
fetcher.setReferencePolicy(ReferenceValidationPolicy.IGNORE);
|
||||
}
|
||||
fetcher.setResolutionContext(cliContext.getResolutionContext());
|
||||
} else {
|
||||
DisabledValidationPolicyAdvisor fetcher = new DisabledValidationPolicyAdvisor();
|
||||
validationEngine.setPolicyAdvisor(fetcher);
|
||||
|
|
|
@ -38,6 +38,8 @@ public class Params {
|
|||
public static final String QUESTIONNAIRE = "-questionnaire";
|
||||
public static final String NATIVE = "-native";
|
||||
public static final String ASSUME_VALID_REST_REF = "-assumeValidRestReferences";
|
||||
public static final String CHECK_REFERENCES = "-check-references";
|
||||
public static final String RESOLUTION_CONTEXT = "-resolution-context";
|
||||
public static final String DEBUG = "-debug";
|
||||
public static final String SCT = "-sct";
|
||||
public static final String RECURSE = "-recurse";
|
||||
|
@ -273,6 +275,10 @@ public class Params {
|
|||
cliContext.setDoNative(true);
|
||||
} else if (args[i].equals(ASSUME_VALID_REST_REF)) {
|
||||
cliContext.setAssumeValidRestReferences(true);
|
||||
} else if (args[i].equals(CHECK_REFERENCES)) {
|
||||
cliContext.setCheckReferences(true);
|
||||
} else if (args[i].equals(RESOLUTION_CONTEXT)) {
|
||||
cliContext.setResolutionContext(args[++i]);
|
||||
} else if (args[i].equals(DEBUG)) {
|
||||
cliContext.setDoDebug(true);
|
||||
} else if (args[i].equals(SCT)) {
|
||||
|
|
|
@ -2023,21 +2023,6 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
return ok;
|
||||
}
|
||||
|
||||
private Set<String> getUnknownSystems(ValidationResult vr) {
|
||||
if (vr == null) {
|
||||
return null;
|
||||
}
|
||||
if (vr.getUnknownSystems() != null && !vr.getUnknownSystems().isEmpty()) {
|
||||
return vr.getUnknownSystems();
|
||||
}
|
||||
if (vr.getSystem() != null) {
|
||||
Set<String> set = new HashSet<String>();
|
||||
set.add(vr.getSystem());
|
||||
return set;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean convertCDACodeToCodeableConcept(List<ValidationMessage> errors, String path, Element element, StructureDefinition logical, CodeableConcept cc) {
|
||||
boolean ok = true;
|
||||
cc.setText(element.getNamedChildValue("originalText", false));
|
||||
|
@ -2525,7 +2510,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
boolean ok = false;
|
||||
CommaSeparatedStringBuilder contexts = new CommaSeparatedStringBuilder();
|
||||
List<String> plist = new ArrayList<>();
|
||||
plist.add(stripIndexes(stack.getLiteralPath()));
|
||||
plist.add(stripIndexes(stripRefs(stack.getLiteralPath())));
|
||||
for (String s : stack.getLogicalPaths()) {
|
||||
String p = stripIndexes(s);
|
||||
// all extensions are always allowed in ElementDefinition.example.value, and in fixed and pattern values. TODO: determine the logical paths from the path stated in the element definition....
|
||||
|
@ -2683,6 +2668,17 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
}
|
||||
}
|
||||
|
||||
private String stripRefs(String literalPath) {
|
||||
if (literalPath.contains(".resolve().ofType(")) {
|
||||
String s = literalPath.substring(literalPath.lastIndexOf(".resolve().")+18);
|
||||
int i = s.indexOf(")");
|
||||
s = s.substring(0, i)+s.substring(i+1);
|
||||
return s;
|
||||
} else {
|
||||
return literalPath;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean containsAny(Set<String> set, List<String> list) {
|
||||
for (String p : list) {
|
||||
if (set.contains(p)) {
|
||||
|
@ -4182,9 +4178,14 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
} else {
|
||||
try {
|
||||
ext = fetcher.fetch(this, valContext.getAppContext(), ref);
|
||||
} catch (IOException e) {
|
||||
} catch (Exception e) {
|
||||
if (STACK_TRACE) e.printStackTrace();
|
||||
throw new FHIRException(e);
|
||||
ext = null;
|
||||
|
||||
// it's probably an error, but here we're just giving the user information about why resolution failed
|
||||
hint(errors, NO_RULE_DATE, IssueType.INFORMATIONAL, element.line(), element.col(), path,
|
||||
false, I18nConstants.REFERENCE_RESOLUTION_FAILED, ref, e.getClass().getName(), e.getMessage());
|
||||
|
||||
}
|
||||
if (ext != null) {
|
||||
setParents(ext);
|
||||
|
|
|
@ -39,6 +39,14 @@ public class BasePolicyAdvisorForFullValidation implements IValidationPolicyAdvi
|
|||
this.refpol = refpol;
|
||||
}
|
||||
|
||||
public ReferenceValidationPolicy getRefpol() {
|
||||
return refpol;
|
||||
}
|
||||
|
||||
public void setRefpol(ReferenceValidationPolicy refpol) {
|
||||
this.refpol = refpol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReferenceValidationPolicy policyForReference(IResourceValidator validator, Object appContext, String path, String url) {
|
||||
return refpol;
|
||||
|
|
|
@ -64,7 +64,12 @@ public class NodeStack {
|
|||
this.context = context;
|
||||
ids = new HashMap<>();
|
||||
this.element = element;
|
||||
literalPath = refPath + "->" + element.getName();
|
||||
int i = element.getName().indexOf(".");
|
||||
if (i == -1) {
|
||||
literalPath = refPath+".resolve().ofType(" + element.getName()+")";
|
||||
} else {
|
||||
literalPath = refPath+".resolve().ofType(" + element.getName().substring(0, i)+")"+element.getName().substring(i);
|
||||
}
|
||||
workingLang = validationLanguage;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,21 +3,30 @@ package org.hl7.fhir.validation.tests;
|
|||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.r5.formats.JsonParser;
|
||||
import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
|
||||
import org.hl7.fhir.r5.model.OperationOutcome;
|
||||
import org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity;
|
||||
import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent;
|
||||
import org.hl7.fhir.r5.test.utils.TestingUtilities;
|
||||
import org.hl7.fhir.r5.utils.OperationOutcomeUtilities;
|
||||
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
|
||||
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
|
||||
import org.hl7.fhir.utilities.FhirPublication;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.filesystem.ManagedFileAccess;
|
||||
import org.hl7.fhir.utilities.settings.FhirSettings;
|
||||
import org.hl7.fhir.utilities.tests.CacheVerificationLogger;
|
||||
import org.hl7.fhir.validation.IgLoader;
|
||||
import org.hl7.fhir.validation.ValidationEngine;
|
||||
import org.hl7.fhir.validation.cli.services.StandAloneValidatorFetcher;
|
||||
import org.hl7.fhir.validation.tests.utilities.TestUtilities;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
|
@ -285,4 +294,149 @@ public class ValidationEngineTests {
|
|||
System.out.println("Finished");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testResolveRelativeFileValid() throws Exception {
|
||||
String folder = setupFolder();
|
||||
try {
|
||||
ValidationEngine ve = TestUtilities.getValidationEngine("hl7.fhir.r4.core#4.0.1", DEF_TX, FhirPublication.R4, "4.0.1");
|
||||
StandAloneValidatorFetcher fetcher = new StandAloneValidatorFetcher(ve.getPcm(), ve.getContext(), ve);
|
||||
ve.setFetcher(fetcher);
|
||||
ve.getContext().setLocator(fetcher);
|
||||
ve.setPolicyAdvisor(fetcher);
|
||||
fetcher.setReferencePolicy(ReferenceValidationPolicy.CHECK_VALID);
|
||||
fetcher.setResolutionContext("file:"+folder);
|
||||
ve.seeResource(new JsonParser().parse(TestingUtilities.loadTestResourceStream("validator", "resolution", "StructureDefinition-Observation.json")));
|
||||
ve.seeResource(new JsonParser().parse(TestingUtilities.loadTestResourceStream("validator", "resolution", "StructureDefinition-Patient.json")));
|
||||
OperationOutcome op = ve.validate(FhirFormat.JSON, TestingUtilities.loadTestResourceStream("validator", "resolution", "relative-url-valid.json"), null);
|
||||
Assertions.assertTrue(checkOutcomes("testResolveRelativeFileValid", op,
|
||||
"Observation null warning/invalid: Best Practice Recommendation: In general, all observations should have a performer\n"+
|
||||
"Observation null warning/invalid: Best Practice Recommendation: In general, all observations should have an effective[x] ()\n"+
|
||||
"Observation null warning/invariant: Constraint failed: dom-6: 'A resource should have narrative for robust management' (defined in http://hl7.org/fhir/StructureDefinition/DomainResource) (Best Practice Recommendation)"));
|
||||
} finally {
|
||||
Utilities.clearDirectory(folder);
|
||||
ManagedFileAccess.file(folder).delete();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveRelativeFileInvalid() throws Exception {
|
||||
String folder = setupFolder();
|
||||
try {
|
||||
ValidationEngine ve = TestUtilities.getValidationEngine("hl7.fhir.r4.core#4.0.1", DEF_TX, FhirPublication.R4, "4.0.1");
|
||||
StandAloneValidatorFetcher fetcher = new StandAloneValidatorFetcher(ve.getPcm(), ve.getContext(), ve);
|
||||
ve.setFetcher(fetcher);
|
||||
ve.getContext().setLocator(fetcher);
|
||||
ve.setPolicyAdvisor(fetcher);
|
||||
fetcher.setReferencePolicy(ReferenceValidationPolicy.CHECK_VALID);
|
||||
fetcher.setResolutionContext("file:"+folder);
|
||||
ve.seeResource(new JsonParser().parse(TestingUtilities.loadTestResourceStream("validator", "resolution", "StructureDefinition-Observation.json")));
|
||||
ve.seeResource(new JsonParser().parse(TestingUtilities.loadTestResourceStream("validator", "resolution", "StructureDefinition-Patient.json")));
|
||||
OperationOutcome op = ve.validate(FhirFormat.JSON, TestingUtilities.loadTestResourceStream("validator", "resolution", "relative-url-invalid.json"), null);
|
||||
Assertions.assertTrue(checkOutcomes("testResolveRelativeFileValid", op,
|
||||
"Observation.subject null error/structure: Unable to find a profile match for Patient/example-newborn among choices: http://hl7.org/fhir/test/StructureDefinition/PatientRule\n"+
|
||||
"Observation.subject null information/structure: Details for Patient/example-newborn matching against profile http://hl7.org/fhir/test/StructureDefinition/PatientRule|0.1.0\n"+
|
||||
"Observation null warning/invalid: Best Practice Recommendation: In general, all observations should have a performer\n"+
|
||||
"Observation null warning/invalid: Best Practice Recommendation: In general, all observations should have an effective[x] ()\n"+
|
||||
"Observation null warning/invariant: Constraint failed: dom-6: 'A resource should have narrative for robust management' (defined in http://hl7.org/fhir/StructureDefinition/DomainResource) (Best Practice Recommendation)"));
|
||||
} finally {
|
||||
Utilities.clearDirectory(folder);
|
||||
ManagedFileAccess.file(folder).delete();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveRelativeFileError() throws Exception {
|
||||
String folder = setupFolder();
|
||||
try {
|
||||
ValidationEngine ve = TestUtilities.getValidationEngine("hl7.fhir.r4.core#4.0.1", DEF_TX, FhirPublication.R4, "4.0.1");
|
||||
StandAloneValidatorFetcher fetcher = new StandAloneValidatorFetcher(ve.getPcm(), ve.getContext(), ve);
|
||||
ve.setFetcher(fetcher);
|
||||
ve.getContext().setLocator(fetcher);
|
||||
ve.setPolicyAdvisor(fetcher);
|
||||
fetcher.setReferencePolicy(ReferenceValidationPolicy.CHECK_VALID);
|
||||
fetcher.setResolutionContext("file:"+folder);
|
||||
ve.seeResource(new JsonParser().parse(TestingUtilities.loadTestResourceStream("validator", "resolution", "StructureDefinition-Observation.json")));
|
||||
ve.seeResource(new JsonParser().parse(TestingUtilities.loadTestResourceStream("validator", "resolution", "StructureDefinition-Patient.json")));
|
||||
OperationOutcome op = ve.validate(FhirFormat.JSON, TestingUtilities.loadTestResourceStream("validator", "resolution", "relative-url-error.json"), null);
|
||||
Assertions.assertTrue(checkOutcomes("testResolveRelativeFileValid", op,
|
||||
"Observation.subject null error/structure: Unable to resolve resource with reference 'patient/example-newborn-x'\n"+
|
||||
"Observation null warning/invalid: Best Practice Recommendation: In general, all observations should have a performer\n"+
|
||||
"Observation null warning/invalid: Best Practice Recommendation: In general, all observations should have an effective[x] ()\n"+
|
||||
"Observation null warning/invariant: Constraint failed: dom-6: 'A resource should have narrative for robust management' (defined in http://hl7.org/fhir/StructureDefinition/DomainResource) (Best Practice Recommendation)"));
|
||||
} finally {
|
||||
Utilities.clearDirectory(folder);
|
||||
ManagedFileAccess.file(folder).delete();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testResolveAbsoluteValid() throws Exception {
|
||||
ValidationEngine ve = TestUtilities.getValidationEngine("hl7.fhir.r4.core#4.0.1", DEF_TX, FhirPublication.R4, "4.0.1");
|
||||
StandAloneValidatorFetcher fetcher = new StandAloneValidatorFetcher(ve.getPcm(), ve.getContext(), ve);
|
||||
ve.setFetcher(fetcher);
|
||||
ve.getContext().setLocator(fetcher);
|
||||
ve.setPolicyAdvisor(fetcher);
|
||||
ve.setShowMessagesFromReferences(true);
|
||||
fetcher.setReferencePolicy(ReferenceValidationPolicy.CHECK_VALID);
|
||||
ve.seeResource(new JsonParser().parse(TestingUtilities.loadTestResourceStream("validator", "resolution", "StructureDefinition-Observation.json")));
|
||||
ve.seeResource(new JsonParser().parse(TestingUtilities.loadTestResourceStream("validator", "resolution", "StructureDefinition-Patient.json")));
|
||||
OperationOutcome op = ve.validate(FhirFormat.JSON, TestingUtilities.loadTestResourceStream("validator", "resolution", "absolute-url-valid.json"), null);
|
||||
Assertions.assertTrue(checkOutcomes("testResolveRelativeFileValid", op,
|
||||
"Observation.subject.resolve().ofType(Patient).managingOrganization null error/structure: Unable to resolve resource with reference 'Organization/1'\n"+
|
||||
"Observation.subject.resolve().ofType(Patient).managingOrganization null information/informational: Fetching 'Organization/1' failed. System details: org.hl7.fhir.exceptions.FHIRException: The URL 'Organization/1' is not known to the FHIR validator, and a resolution context has not been provided as part of the setup / parameters\n"+
|
||||
"Observation null warning/invalid: Best Practice Recommendation: In general, all observations should have a performer\n"+
|
||||
"Observation null warning/invalid: Best Practice Recommendation: In general, all observations should have an effective[x] ()\n"+
|
||||
"Observation null warning/invariant: Constraint failed: dom-6: 'A resource should have narrative for robust management' (defined in http://hl7.org/fhir/StructureDefinition/DomainResource) (Best Practice Recommendation)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveAbsoluteInvalid() throws Exception {
|
||||
ValidationEngine ve = TestUtilities.getValidationEngine("hl7.fhir.r4.core#4.0.1", DEF_TX, FhirPublication.R4, "4.0.1");
|
||||
StandAloneValidatorFetcher fetcher = new StandAloneValidatorFetcher(ve.getPcm(), ve.getContext(), ve);
|
||||
ve.setFetcher(fetcher);
|
||||
ve.getContext().setLocator(fetcher);
|
||||
ve.setPolicyAdvisor(fetcher);
|
||||
fetcher.setReferencePolicy(ReferenceValidationPolicy.CHECK_VALID);
|
||||
ve.seeResource(new JsonParser().parse(TestingUtilities.loadTestResourceStream("validator", "resolution", "StructureDefinition-Observation.json")));
|
||||
ve.seeResource(new JsonParser().parse(TestingUtilities.loadTestResourceStream("validator", "resolution", "StructureDefinition-Patient.json")));
|
||||
OperationOutcome op = ve.validate(FhirFormat.JSON, TestingUtilities.loadTestResourceStream("validator", "resolution", "absolute-url-invalid.json"), null);
|
||||
Assertions.assertTrue(checkOutcomes("testResolveRelativeFileValid", op,
|
||||
"Observation.subject null error/structure: Unable to find a profile match for https://hl7.org/fhir/R4/patient-example-newborn.json among choices: http://hl7.org/fhir/test/StructureDefinition/PatientRule\n"+
|
||||
"Observation.subject null information/structure: Details for https://hl7.org/fhir/R4/patient-example-newborn.json matching against profile http://hl7.org/fhir/test/StructureDefinition/PatientRule|0.1.0\n"+
|
||||
"Observation null warning/invalid: Best Practice Recommendation: In general, all observations should have a performer\n"+
|
||||
"Observation null warning/invalid: Best Practice Recommendation: In general, all observations should have an effective[x] ()\n"+
|
||||
"Observation null warning/invariant: Constraint failed: dom-6: 'A resource should have narrative for robust management' (defined in http://hl7.org/fhir/StructureDefinition/DomainResource) (Best Practice Recommendation)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveAbsoluteError() throws Exception {
|
||||
ValidationEngine ve = TestUtilities.getValidationEngine("hl7.fhir.r4.core#4.0.1", DEF_TX, FhirPublication.R4, "4.0.1");
|
||||
StandAloneValidatorFetcher fetcher = new StandAloneValidatorFetcher(ve.getPcm(), ve.getContext(), ve);
|
||||
ve.setFetcher(fetcher);
|
||||
ve.getContext().setLocator(fetcher);
|
||||
ve.setPolicyAdvisor(fetcher);
|
||||
fetcher.setReferencePolicy(ReferenceValidationPolicy.CHECK_VALID);
|
||||
ve.seeResource(new JsonParser().parse(TestingUtilities.loadTestResourceStream("validator", "resolution", "StructureDefinition-Observation.json")));
|
||||
ve.seeResource(new JsonParser().parse(TestingUtilities.loadTestResourceStream("validator", "resolution", "StructureDefinition-Patient.json")));
|
||||
OperationOutcome op = ve.validate(FhirFormat.JSON, TestingUtilities.loadTestResourceStream("validator", "resolution", "absolute-url-error.json"), null);
|
||||
Assertions.assertTrue(checkOutcomes("testResolveRelativeFileValid", op,
|
||||
"Observation.subject null error/structure: Unable to resolve resource with reference 'http://hl7x.org/fhir/R4/Patient/Patient/example-newborn'\n"+
|
||||
"Observation.subject null information/informational: Fetching 'http://hl7x.org/fhir/R4/Patient/Patient/example-newborn' failed. System details: java.net.UnknownHostException: hl7x.org\n"+
|
||||
"Observation null warning/invalid: Best Practice Recommendation: In general, all observations should have a performer\n"+
|
||||
"Observation null warning/invalid: Best Practice Recommendation: In general, all observations should have an effective[x] ()\n"+
|
||||
"Observation null warning/invariant: Constraint failed: dom-6: 'A resource should have narrative for robust management' (defined in http://hl7.org/fhir/StructureDefinition/DomainResource) (Best Practice Recommendation)"));
|
||||
}
|
||||
|
||||
private String setupFolder() throws IOException {
|
||||
String now = new SimpleDateFormat("yyyymmddhhMMss").format(new Date());
|
||||
String folder = Utilities.path("[tmp]", "validator-resolution", now);
|
||||
Utilities.createDirectory(folder);
|
||||
for (String s : Utilities.strings("Organization-first.xml", "Patient-example-newborn.json", "patient-example.json")) {
|
||||
TextFile.bytesToFile( TestingUtilities.loadTestResourceBytes("validator", "resolution", s), Utilities.path(folder, s));
|
||||
}
|
||||
return folder;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue