001package org.hl7.fhir.common.hapi.validation.support; 002 003import ca.uhn.fhir.context.FhirContext; 004import ca.uhn.fhir.context.support.ConceptValidationOptions; 005import ca.uhn.fhir.context.support.ValidationSupportContext; 006import org.hl7.fhir.instance.model.api.IBaseResource; 007import org.slf4j.Logger; 008import org.slf4j.LoggerFactory; 009 010import javax.annotation.Nonnull; 011import javax.annotation.Nullable; 012 013/** 014 * This validation support module may be placed at the end of a {@link ValidationSupportChain} 015 * in order to configure the validator to generate a warning if a resource being validated 016 * contains an unknown code system. 017 * 018 * Note that this module must also be activated by calling {@link #setAllowNonExistentCodeSystem(boolean)} 019 * in order to specify that unknown code systems should be allowed. 020 */ 021public class UnknownCodeSystemWarningValidationSupport extends BaseValidationSupport { 022 private static final Logger ourLog = LoggerFactory.getLogger(UnknownCodeSystemWarningValidationSupport.class); 023 024 public static final IssueSeverity DEFAULT_SEVERITY = IssueSeverity.ERROR; 025 026 private IssueSeverity myNonExistentCodeSystemSeverity = DEFAULT_SEVERITY; 027 028 /** 029 * Constructor 030 */ 031 public UnknownCodeSystemWarningValidationSupport(FhirContext theFhirContext) { 032 super(theFhirContext); 033 } 034 035 @Override 036 public boolean isValueSetSupported(ValidationSupportContext theValidationSupportContext, String theValueSetUrl) { 037 return true; 038 } 039 040 @Override 041 public boolean isCodeSystemSupported(ValidationSupportContext theValidationSupportContext, String theSystem) { 042 return canValidateCodeSystem(theValidationSupportContext, theSystem); 043 } 044 045 @Override 046 public CodeValidationResult validateCode(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, String theValueSetUrl) { 047 // filters out error/fatal 048 // NB: this is a secondary check. isCodeSystemSupported 049 // should prevent this from ever calling validate code here 050 // ... but should it ever get called, we'll return null 051 if (!canValidateCodeSystem(theValidationSupportContext, theCodeSystem)) { 052 return null; 053 } 054 055 CodeValidationResult result = new CodeValidationResult() 056 .setSeverity(myNonExistentCodeSystemSeverity); // will be warning or info (error/fatal filtered out above) 057 058 result.setMessage("No issues detected during validation"); 059 060 switch (myNonExistentCodeSystemSeverity) { 061 case INFORMATION: 062 // for warnings, we don't set the code 063 // cause if we do, the severity is stripped out 064 // (see VersionSpecificWorkerContextWrapper.convertValidationResult) 065 result.setCode(theCode); 066 break; 067 } 068 069 return result; 070 } 071 072 @Nullable 073 @Override 074 public CodeValidationResult validateCodeInValueSet(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, @Nonnull IBaseResource theValueSet) { 075 if (!canValidateCodeSystem(theValidationSupportContext, theCodeSystem)) { 076 return null; 077 } 078 079 return new CodeValidationResult() 080 .setCode(theCode) 081 .setSeverity(IssueSeverity.INFORMATION) 082 .setMessage("Code " + theCodeSystem + "#" + theCode + " was not checked because the CodeSystem is not available"); 083 } 084 085 /** 086 * Returns true if non existent code systems will still validate. 087 * False if they will throw errors. 088 * @return 089 */ 090 private boolean allowNonExistentCodeSystems() { 091 switch (myNonExistentCodeSystemSeverity) { 092 case ERROR: 093 case FATAL: 094 return false; 095 case WARNING: 096 case INFORMATION: 097 return true; 098 default: 099 ourLog.info("Unknown issue severity " + myNonExistentCodeSystemSeverity.name() 100 + ". Treating as INFO/WARNING"); 101 return true; 102 } 103 } 104 105 /** 106 * Determines if the code system can (and should) be validated. 107 * @param theValidationSupportContext 108 * @param theCodeSystem 109 * @return 110 */ 111 private boolean canValidateCodeSystem(ValidationSupportContext theValidationSupportContext, 112 String theCodeSystem) { 113 if (!allowNonExistentCodeSystems()) { 114 return false; 115 } 116 if (theCodeSystem == null) { 117 return false; 118 } 119 IBaseResource codeSystem = theValidationSupportContext.getRootValidationSupport().fetchCodeSystem(theCodeSystem); 120 if (codeSystem != null) { 121 return false; 122 } 123 return true; 124 } 125 126 /** 127 * If set to allow, code system violations will be flagged with Warning by default. 128 * Use setNonExistentCodeSystemSeverity instead. 129 * 130 * @param theAllowNonExistentCodeSystem 131 */ 132 @Deprecated 133 public void setAllowNonExistentCodeSystem(boolean theAllowNonExistentCodeSystem) { 134 if (theAllowNonExistentCodeSystem) { 135 setNonExistentCodeSystemSeverity(IssueSeverity.WARNING); 136 } else { 137 setNonExistentCodeSystemSeverity(IssueSeverity.ERROR); 138 } 139 } 140 141 /** 142 * Sets the non-existent code system severity. 143 * @param theSeverity 144 */ 145 public void setNonExistentCodeSystemSeverity(IssueSeverity theSeverity) { 146 myNonExistentCodeSystemSeverity = theSeverity; 147 } 148}