
001package org.hl7.fhir.dstu3.hapi.ctx; 002 003import ca.uhn.fhir.context.FhirContext; 004import ca.uhn.fhir.context.support.ConceptValidationOptions; 005import ca.uhn.fhir.context.support.IValidationSupport; 006import ca.uhn.fhir.context.support.ValidationSupportContext; 007import ca.uhn.fhir.i18n.Msg; 008import ca.uhn.fhir.rest.api.Constants; 009import ca.uhn.fhir.sl.cache.Cache; 010import ca.uhn.fhir.sl.cache.CacheFactory; 011import ca.uhn.fhir.system.HapiSystemProperties; 012import ca.uhn.fhir.util.CoverageIgnore; 013import org.apache.commons.lang3.Validate; 014import org.hl7.fhir.dstu3.context.IWorkerContext; 015import org.hl7.fhir.dstu3.formats.IParser; 016import org.hl7.fhir.dstu3.formats.ParserType; 017import org.hl7.fhir.dstu3.model.CodeSystem; 018import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent; 019import org.hl7.fhir.dstu3.model.CodeableConcept; 020import org.hl7.fhir.dstu3.model.Coding; 021import org.hl7.fhir.dstu3.model.ConceptMap; 022import org.hl7.fhir.dstu3.model.ExpansionProfile; 023import org.hl7.fhir.dstu3.model.MetadataResource; 024import org.hl7.fhir.dstu3.model.Resource; 025import org.hl7.fhir.dstu3.model.ResourceType; 026import org.hl7.fhir.dstu3.model.StructureDefinition; 027import org.hl7.fhir.dstu3.model.ValueSet; 028import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent; 029import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionComponent; 030import org.hl7.fhir.dstu3.terminologies.ValueSetExpander; 031import org.hl7.fhir.dstu3.utils.INarrativeGenerator; 032import org.hl7.fhir.dstu3.utils.validation.IResourceValidator; 033import org.hl7.fhir.exceptions.FHIRException; 034import org.hl7.fhir.utilities.i18n.I18nBase; 035import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; 036import org.hl7.fhir.utilities.validation.ValidationOptions; 037import org.slf4j.Logger; 038import org.slf4j.LoggerFactory; 039 040import java.util.ArrayList; 041import java.util.Arrays; 042import java.util.Collections; 043import java.util.HashSet; 044import java.util.List; 045import java.util.Set; 046 047import static org.apache.commons.lang3.StringUtils.isNotBlank; 048 049public final class HapiWorkerContext extends I18nBase implements IWorkerContext { 050 private static final Logger ourLog = LoggerFactory.getLogger(HapiWorkerContext.class); 051 private final FhirContext myCtx; 052 private final Cache<String, Resource> myFetchedResourceCache; 053 private IValidationSupport myValidationSupport; 054 private ExpansionProfile myExpansionProfile; 055 056 public HapiWorkerContext(FhirContext theCtx, IValidationSupport theValidationSupport) { 057 Validate.notNull(theCtx, "theCtx must not be null"); 058 Validate.notNull(theValidationSupport, "theValidationSupport must not be null"); 059 myCtx = theCtx; 060 myValidationSupport = theValidationSupport; 061 062 long timeoutMillis = HapiSystemProperties.getTestValidationResourceCachesMs(); 063 myFetchedResourceCache = CacheFactory.build(timeoutMillis); 064 // Set a default locale 065 setValidationMessageLanguage(getLocale()); 066 } 067 068 @Override 069 @CoverageIgnore 070 public List<MetadataResource> allConformanceResources() { 071 throw new UnsupportedOperationException(Msg.code(610)); 072 } 073 074 @Override 075 public List<StructureDefinition> allStructures() { 076 return myValidationSupport.fetchAllStructureDefinitions(); 077 } 078 079 @Override 080 public ValueSetExpansionComponent expandVS(ConceptSetComponent theInc, boolean theHierarchical) { 081 ValueSet input = new ValueSet(); 082 input.getCompose().addInclude(theInc); 083 IValidationSupport.ValueSetExpansionOutcome output = myValidationSupport.expandValueSet(new ValidationSupportContext(myValidationSupport), null, input); 084 ValueSet outputValueSet = (ValueSet) output.getValueSet(); 085 if (outputValueSet != null) { 086 return outputValueSet.getExpansion(); 087 } else { 088 return null; 089 } 090 } 091 092 @Override 093 public StructureDefinition fetchTypeDefinition(String theCode) { 094 return fetchResource(org.hl7.fhir.dstu3.model.StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + theCode); 095 } 096 097 @Override 098 public CodeSystem fetchCodeSystem(String theSystem) { 099 if (myValidationSupport == null) { 100 return null; 101 } else { 102 return (CodeSystem) myValidationSupport.fetchCodeSystem(theSystem); 103 } 104 } 105 106 @Override 107 public <T extends Resource> T fetchResource(Class<T> theClass, String theUri) { 108 Validate.notBlank(theUri, "theUri must not be null or blank"); 109 if (myValidationSupport == null) { 110 return null; 111 } else { 112 try { 113 //noinspection unchecked 114 return (T) myFetchedResourceCache.get(theUri, t -> { 115 T resource = myValidationSupport.fetchResource(theClass, theUri); 116 if (resource == null) { 117 throw new IllegalArgumentException(Msg.code(611)); 118 } 119 return resource; 120 }); 121 } catch (IllegalArgumentException e) { 122 return null; 123 } 124 } 125 } 126 127 @Override 128 public <T extends Resource> T fetchResourceWithException(Class<T> theClass_, String theUri) throws FHIRException { 129 T retVal = fetchResource(theClass_, theUri); 130 if (retVal == null) { 131 throw new FHIRException(Msg.code(612) + "Unable to fetch " + theUri); 132 } 133 return retVal; 134 } 135 136 @Override 137 public List<ConceptMap> findMapsForSource(String theUrl) { 138 throw new UnsupportedOperationException(Msg.code(613)); 139 } 140 141 @Override 142 public ValueSetExpander.ValueSetExpansionOutcome expandVS(ValueSet source, boolean cacheOk, boolean heiarchical) { 143 throw new UnsupportedOperationException(Msg.code(614)); 144 } 145 146 @Override 147 public String getAbbreviation(String theName) { 148 throw new UnsupportedOperationException(Msg.code(615)); 149 } 150 151 @Override 152 public ExpansionProfile getExpansionProfile() { 153 return myExpansionProfile; 154 } 155 156 @Override 157 public void setExpansionProfile(ExpansionProfile theExpProfile) { 158 myExpansionProfile = theExpProfile; 159 } 160 161 @Override 162 public INarrativeGenerator getNarrativeGenerator(String thePrefix, String theBasePath) { 163 throw new UnsupportedOperationException(Msg.code(616)); 164 } 165 166 @Override 167 public IResourceValidator newValidator() throws FHIRException { 168 throw new UnsupportedOperationException(Msg.code(617)); 169 } 170 171 @Override 172 public IParser getParser(ParserType theType) { 173 throw new UnsupportedOperationException(Msg.code(618)); 174 } 175 176 @Override 177 public IParser getParser(String theType) { 178 throw new UnsupportedOperationException(Msg.code(619)); 179 } 180 181 @Override 182 public List<String> getResourceNames() { 183 List<String> result = new ArrayList<>(); 184 for (ResourceType next : ResourceType.values()) { 185 result.add(next.name()); 186 } 187 Collections.sort(result); 188 return result; 189 } 190 191 @Override 192 public Set<String> getResourceNamesAsSet() { 193 return new HashSet<>(getResourceNames()); 194 } 195 196 @Override 197 public List<String> getTypeNames() { 198 throw new UnsupportedOperationException(Msg.code(620)); 199 } 200 201 @Override 202 public String getVersion() { 203 return myCtx.getVersion().getVersion().getFhirVersionString(); 204 } 205 206 @Override 207 @CoverageIgnore 208 public boolean hasCache() { 209 throw new UnsupportedOperationException(Msg.code(621)); 210 } 211 212 @Override 213 public <T extends Resource> boolean hasResource(Class<T> theClass_, String theUri) { 214 throw new UnsupportedOperationException(Msg.code(622)); 215 } 216 217 @Override 218 public boolean isNoTerminologyServer() { 219 return false; 220 } 221 222 @Override 223 public IParser newJsonParser() { 224 throw new UnsupportedOperationException(Msg.code(623)); 225 } 226 227 @Override 228 public IParser newXmlParser() { 229 throw new UnsupportedOperationException(Msg.code(624)); 230 } 231 232 @Override 233 public String oid2Uri(String theCode) { 234 throw new UnsupportedOperationException(Msg.code(625)); 235 } 236 237 @Override 238 public void setLogger(ILoggingService theLogger) { 239 throw new UnsupportedOperationException(Msg.code(626)); 240 } 241 242 @Override 243 public boolean supportsSystem(String theSystem) { 244 if (myValidationSupport == null) { 245 return false; 246 } else { 247 return myValidationSupport.isCodeSystemSupported(new ValidationSupportContext(myValidationSupport), theSystem); 248 } 249 } 250 251 @Override 252 public Set<String> typeTails() { 253 return new HashSet<>(Arrays.asList("Integer", "UnsignedInt", "PositiveInt", "Decimal", "DateTime", "Date", "Time", "Instant", "String", "Uri", "Oid", "Uuid", "Id", "Boolean", "Code", 254 "Markdown", "Base64Binary", "Coding", "CodeableConcept", "Attachment", "Identifier", "Quantity", "SampledData", "Range", "Period", "Ratio", "HumanName", "Address", "ContactPoint", 255 "Timing", "Reference", "Annotation", "Signature", "Meta")); 256 } 257 258 @Override 259 public ValidationResult validateCode(CodeableConcept theCode, ValueSet theVs) { 260 for (Coding next : theCode.getCoding()) { 261 ValidationResult retVal = validateCode(next, theVs); 262 if (retVal.isOk()) { 263 return retVal; 264 } 265 } 266 267 return new ValidationResult(IssueSeverity.ERROR, null); 268 } 269 270 @Override 271 public ValidationResult validateCode(Coding theCode, ValueSet theVs) { 272 String system = theCode.getSystem(); 273 String code = theCode.getCode(); 274 String display = theCode.getDisplay(); 275 return validateCode(system, code, display, theVs); 276 } 277 278 @Override 279 public ValidationResult validateCode(String theSystem, String theCode, String theDisplay) { 280 ValidationOptions options = new ValidationOptions(); 281 IValidationSupport.CodeValidationResult result = myValidationSupport.validateCode(new ValidationSupportContext(myValidationSupport), convertConceptValidationOptions(options), theSystem, theCode, theDisplay, null); 282 if (result == null) { 283 return null; 284 } 285 286 IssueSeverity severity = null; 287 if (result.getSeverity() != null) { 288 severity = IssueSeverity.fromCode(result.getSeverityCode()); 289 } 290 ConceptDefinitionComponent definition = new ConceptDefinitionComponent().setCode(result.getCode()); 291 return new ValidationResult(severity, result.getMessage(), definition); 292 } 293 294 public static ConceptValidationOptions convertConceptValidationOptions(ValidationOptions theOptions) { 295 ConceptValidationOptions retVal = new ConceptValidationOptions(); 296 if (theOptions.isGuessSystem()) { 297 retVal = retVal.setInferSystem(true); 298 } 299 return retVal; 300 } 301 302 @Override 303 public ValidationResult validateCode(String theSystem, String theCode, String theDisplay, ConceptSetComponent theVsi) { 304 throw new UnsupportedOperationException(Msg.code(627)); 305 } 306 307 @Override 308 public ValidationResult validateCode(String theSystem, String theCode, String theDisplay, ValueSet theVs) { 309 310 IValidationSupport.CodeValidationResult outcome; 311 ValidationOptions options = new ValidationOptions(); 312 if (isNotBlank(theVs.getUrl())) { 313 outcome = myValidationSupport.validateCode(new ValidationSupportContext(myValidationSupport), convertConceptValidationOptions(options), theSystem, theCode, theDisplay, theVs.getUrl()); 314 } else { 315 outcome = myValidationSupport.validateCodeInValueSet(new ValidationSupportContext(myValidationSupport), convertConceptValidationOptions(options), theSystem, theCode, theDisplay, theVs); 316 } 317 318 if (outcome != null && outcome.isOk()) { 319 ConceptDefinitionComponent definition = new ConceptDefinitionComponent(); 320 definition.setCode(theCode); 321 definition.setDisplay(outcome.getDisplay()); 322 return new ValidationResult(definition); 323 } 324 325 return new ValidationResult(IssueSeverity.ERROR, "Unknown code[" + theCode + "] in system[" + Constants.codeSystemWithDefaultDescription(theSystem) + "]"); 326 } 327 328}