
001package org.hl7.fhir.r5.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 org.apache.commons.lang3.Validate; 013import org.fhir.ucum.UcumService; 014import org.hl7.fhir.exceptions.FHIRException; 015import org.hl7.fhir.r5.context.ExpansionOptions; 016import org.hl7.fhir.r5.context.IOIDServices; 017import org.hl7.fhir.r5.context.IWorkerContext; 018import org.hl7.fhir.r5.context.IWorkerContextManager; 019import org.hl7.fhir.r5.model.CodeSystem; 020import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent; 021import org.hl7.fhir.r5.model.CodeableConcept; 022import org.hl7.fhir.r5.model.Coding; 023import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent; 024import org.hl7.fhir.r5.model.NamingSystem; 025import org.hl7.fhir.r5.model.OperationOutcome; 026import org.hl7.fhir.r5.model.PackageInformation; 027import org.hl7.fhir.r5.model.Parameters; 028import org.hl7.fhir.r5.model.Resource; 029import org.hl7.fhir.r5.model.ResourceType; 030import org.hl7.fhir.r5.model.StructureDefinition; 031import org.hl7.fhir.r5.model.ValueSet; 032import org.hl7.fhir.r5.profilemodel.PEBuilder; 033import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpansionOutcome; 034import org.hl7.fhir.r5.terminologies.utilities.CodingValidationRequest; 035import org.hl7.fhir.r5.terminologies.utilities.ValidationResult; 036import org.hl7.fhir.r5.utils.validation.IResourceValidator; 037import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier; 038import org.hl7.fhir.utilities.FhirPublication; 039import org.hl7.fhir.utilities.TimeTracker; 040import org.hl7.fhir.utilities.i18n.I18nBase; 041import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; 042import org.hl7.fhir.utilities.validation.ValidationOptions; 043 044import java.util.ArrayList; 045import java.util.Collections; 046import java.util.List; 047import java.util.Locale; 048import java.util.Map; 049import java.util.Set; 050 051import static org.apache.commons.lang3.StringUtils.isNotBlank; 052 053public final class HapiWorkerContext extends I18nBase implements IWorkerContext { 054 private final FhirContext myCtx; 055 private final Cache<String, Resource> myFetchedResourceCache; 056 private final IValidationSupport myValidationSupport; 057 private Parameters myExpansionProfile; 058 private String myOverrideVersionNs; 059 060 public HapiWorkerContext(FhirContext theCtx, IValidationSupport theValidationSupport) { 061 Validate.notNull(theCtx, "theCtx must not be null"); 062 Validate.notNull(theValidationSupport, "theValidationSupport must not be null"); 063 myCtx = theCtx; 064 myValidationSupport = theValidationSupport; 065 066 long timeoutMillis = HapiSystemProperties.getValidationResourceCacheTimeoutMillis(); 067 068 myFetchedResourceCache = CacheFactory.build(timeoutMillis); 069 070 // Set a default locale 071 setValidationMessageLanguage(getLocale()); 072 } 073 074 @Override 075 public CodeSystem fetchCodeSystem(String theSystem) { 076 if (myValidationSupport == null) { 077 return null; 078 } else { 079 return (CodeSystem) myValidationSupport.fetchCodeSystem(theSystem); 080 } 081 } 082 083 @Override 084 public CodeSystem fetchCodeSystem(String theSystem, String version, Resource sourceOfReference) { 085 if (myValidationSupport == null) { 086 return null; 087 } else { 088 return (CodeSystem) myValidationSupport.fetchCodeSystem(theSystem); 089 } 090 } 091 092 @Override 093 public CodeSystem fetchSupplementedCodeSystem(String theS) { 094 return null; 095 } 096 097 @Override 098 public CodeSystem fetchSupplementedCodeSystem(String system, String version, Resource sourceOfReference) { 099 return null; 100 } 101 102 @Override 103 public List<String> getResourceNames() { 104 List<String> result = new ArrayList<>(); 105 for (ResourceType next : ResourceType.values()) { 106 result.add(next.name()); 107 } 108 Collections.sort(result); 109 return result; 110 } 111 112 @Override 113 public IResourceValidator newValidator() { 114 throw new UnsupportedOperationException(Msg.code(206)); 115 } 116 117 @Override 118 public Map<String, NamingSystem> getNSUrlMap() { 119 throw new UnsupportedOperationException(Msg.code(2241)); 120 } 121 122 @Override 123 public SystemSupportInformation getTxSupportInfo(String system, String version) { 124 return null; 125 } 126 127 @Override 128 public ValidationResult validateCode(ValidationOptions theOptions, CodeableConcept theCode, ValueSet theVs) { 129 for (Coding next : theCode.getCoding()) { 130 ValidationResult retVal = validateCode(theOptions, next, theVs); 131 if (retVal.isOk()) { 132 return retVal; 133 } 134 } 135 136 return new ValidationResult(IssueSeverity.ERROR, null, null); 137 } 138 139 @Override 140 public ValidationResult validateCode(ValidationOptions theOptions, Coding theCode, ValueSet theVs) { 141 String system = theCode.getSystem(); 142 String code = theCode.getCode(); 143 String display = theCode.getDisplay(); 144 return validateCode(theOptions, system, null, code, display, theVs); 145 } 146 147 @Override 148 public ValidationResult validateCode( 149 ValidationOptions options, Coding code, ValueSet vs, ValidationContextCarrier ctxt) { 150 return validateCode(options, code, vs); 151 } 152 153 @Override 154 public void validateCodeBatch( 155 ValidationOptions options, List<? extends CodingValidationRequest> codes, ValueSet vs, boolean passVS) {} 156 157 @Override 158 public ValidationResult validateCode( 159 ValidationOptions theOptions, String theSystem, String theVersion, String theCode, String theDisplay) { 160 IValidationSupport.CodeValidationResult result = myValidationSupport.validateCode( 161 new ValidationSupportContext(myValidationSupport), 162 convertConceptValidationOptions(theOptions), 163 theSystem, 164 theCode, 165 theDisplay, 166 null); 167 if (result == null) { 168 return null; 169 } 170 IssueSeverity severity = null; 171 if (result.getSeverity() != null) { 172 severity = IssueSeverity.fromCode(result.getSeverityCode()); 173 } 174 ConceptDefinitionComponent definition = new ConceptDefinitionComponent().setCode(result.getCode()); 175 return new ValidationResult(severity, result.getMessage(), theSystem, theVersion, definition, null, null); 176 } 177 178 @Override 179 public ValidationResult validateCode( 180 ValidationOptions theOptions, 181 String theSystem, 182 String theVersion, 183 String theCode, 184 String theDisplay, 185 ValueSet theVs) { 186 IValidationSupport.CodeValidationResult outcome; 187 if (isNotBlank(theVs.getUrl())) { 188 outcome = myValidationSupport.validateCode( 189 new ValidationSupportContext(myValidationSupport), 190 convertConceptValidationOptions(theOptions), 191 theSystem, 192 theCode, 193 theDisplay, 194 theVs.getUrl()); 195 } else { 196 outcome = myValidationSupport.validateCodeInValueSet( 197 new ValidationSupportContext(myValidationSupport), 198 convertConceptValidationOptions(theOptions), 199 theSystem, 200 theCode, 201 theDisplay, 202 theVs); 203 } 204 205 if (outcome != null && outcome.isOk()) { 206 ConceptDefinitionComponent definition = new ConceptDefinitionComponent(); 207 definition.setCode(theCode); 208 definition.setDisplay(outcome.getDisplay()); 209 return new ValidationResult(theSystem, theVersion, definition, null); 210 } 211 212 return new ValidationResult( 213 IssueSeverity.ERROR, 214 "Unknown code[" + theCode + "] in system[" + Constants.codeSystemWithDefaultDescription(theSystem) 215 + "]", 216 null); 217 } 218 219 @Override 220 public ValidationResult validateCode(ValidationOptions theOptions, String code, ValueSet vs) { 221 return validateCode(theOptions, null, null, code, null, vs); 222 } 223 224 @Override 225 public Parameters getExpansionParameters() { 226 return myExpansionProfile; 227 } 228 229 public void setExpansionProfile(Parameters theExpParameters) { 230 myExpansionProfile = theExpParameters; 231 } 232 233 @Override 234 public ValueSetExpansionOutcome expandVS(ValueSet theSource, boolean theCacheOk, boolean theHierarchical) { 235 throw new UnsupportedOperationException(Msg.code(2128)); 236 } 237 238 @Override 239 public ValueSetExpansionOutcome expandVS(ExpansionOptions options, ValueSet source) { 240 throw new UnsupportedOperationException(Msg.code(2823)); 241 } 242 243 @Override 244 public ValueSetExpansionOutcome expandVS(ValueSet theSource, boolean theCacheOk, boolean theHierarchical, int i) { 245 throw new UnsupportedOperationException(Msg.code(2650)); 246 } 247 248 @Override 249 public ValueSetExpansionOutcome expandVS(ExpansionOptions options, String uri) { 250 throw new UnsupportedOperationException(Msg.code(2824)); 251 } 252 253 @Override 254 public Locale getLocale() { 255 return Locale.getDefault(); 256 } 257 258 @Override 259 public void setLocale(Locale locale) { 260 // ignore 261 } 262 263 @Override 264 public org.hl7.fhir.r5.context.ILoggingService getLogger() { 265 throw new UnsupportedOperationException(Msg.code(213)); 266 } 267 268 @Override 269 public String getVersion() { 270 return myCtx.getVersion().getVersion().getFhirVersionString(); 271 } 272 273 @Override 274 public UcumService getUcumService() { 275 throw new UnsupportedOperationException(Msg.code(216)); 276 } 277 278 @Override 279 public IOIDServices oidServices() { 280 throw new UnsupportedOperationException(Msg.code(2825)); 281 } 282 283 @Override 284 public IWorkerContextManager getManager() { 285 throw new UnsupportedOperationException(Msg.code(2826)); 286 } 287 288 @Override 289 public boolean isNoTerminologyServer() { 290 return false; 291 } 292 293 @Override 294 public Set<String> getCodeSystemsUsed() { 295 throw new UnsupportedOperationException(Msg.code(218)); 296 } 297 298 @Override 299 public StructureDefinition fetchTypeDefinition(String typeName) { 300 return fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + typeName); 301 } 302 303 @Override 304 public boolean isPrimitiveType(String s) { 305 throw new UnsupportedOperationException(Msg.code(2462)); 306 } 307 308 @Override 309 public boolean isDataType(String s) { 310 throw new UnsupportedOperationException(Msg.code(2463)); 311 } 312 313 @Override 314 public List<StructureDefinition> fetchTypeDefinitions(String n) { 315 throw new UnsupportedOperationException(Msg.code(234)); 316 } 317 318 @Override 319 public <T extends Resource> T fetchResourceRaw(Class<T> class_, String uri) { 320 return fetchResource(class_, uri); 321 } 322 323 @Override 324 public <T extends org.hl7.fhir.r5.model.Resource> T fetchResource(Class<T> theClass, String theUri) { 325 if (myValidationSupport == null || theUri == null) { 326 return null; 327 } else { 328 @SuppressWarnings("unchecked") 329 T retVal = (T) myFetchedResourceCache.get(theUri, t -> myValidationSupport.fetchResource(theClass, theUri)); 330 return retVal; 331 } 332 } 333 334 public <T extends Resource> T fetchResource(Class<T> class_, String uri, FhirPublication fhirVersion) { 335 throw new UnsupportedOperationException(Msg.code(2466)); 336 } 337 338 @Override 339 public <T extends org.hl7.fhir.r5.model.Resource> T fetchResourceWithException(Class<T> theClass, String theUri) 340 throws FHIRException { 341 T retVal = fetchResource(theClass, theUri); 342 if (retVal == null) { 343 throw new FHIRException(Msg.code(224) + "Could not find resource: " + theUri); 344 } 345 return retVal; 346 } 347 348 @Override 349 public <T extends Resource> T fetchResourceWithException( 350 Class<T> theClass, String uri, String version, Resource sourceOfReference) throws FHIRException { 351 throw new UnsupportedOperationException(Msg.code(2213)); 352 } 353 354 @Override 355 public <T extends Resource> T fetchResource( 356 Class<T> theClass, String theUri, String theVersion, Resource sourceOfReference) { 357 if (theVersion == null) { 358 return fetchResource(theClass, theUri); 359 } 360 return fetchResource(theClass, theUri + "|" + theVersion); 361 } 362 363 @Override 364 public org.hl7.fhir.r5.model.Resource fetchResourceById(String theType, String theUri) { 365 throw new UnsupportedOperationException(Msg.code(226)); 366 } 367 368 @Override 369 public <T extends org.hl7.fhir.r5.model.Resource> boolean hasResource(Class<T> theClass_, String theUri) { 370 throw new UnsupportedOperationException(Msg.code(227)); 371 } 372 373 @Override 374 public <T extends Resource> boolean hasResource( 375 Class<T> class_, String uri, String version, Resource sourceOfReference) { 376 throw new UnsupportedOperationException(Msg.code(2470)); 377 } 378 379 @Override 380 public Set<String> getResourceNamesAsSet() { 381 return myCtx.getResourceTypes(); 382 } 383 384 @Override 385 public ValueSetExpansionOutcome expandVS( 386 Resource src, ElementDefinitionBindingComponent theBinding, boolean theCacheOk, boolean theHierarchical) 387 throws FHIRException { 388 throw new UnsupportedOperationException(Msg.code(230)); 389 } 390 391 @Override 392 public Set<String> getBinaryKeysAsSet() { 393 throw new UnsupportedOperationException(Msg.code(2115)); 394 } 395 396 @Override 397 public boolean hasBinaryKey(String s) { 398 throw new UnsupportedOperationException(Msg.code(2129)); 399 } 400 401 @Override 402 public byte[] getBinaryForKey(String s) { 403 throw new UnsupportedOperationException(Msg.code(2199)); 404 } 405 406 @Override 407 public boolean hasPackage(String id, String ver) { 408 throw new UnsupportedOperationException(Msg.code(236)); 409 } 410 411 @Override 412 public boolean hasPackage(PackageInformation packageVersion) { 413 return false; 414 } 415 416 @Override 417 public PackageInformation getPackage(String id, String ver) { 418 return null; 419 } 420 421 @Override 422 public int getClientRetryCount() { 423 throw new UnsupportedOperationException(Msg.code(237)); 424 } 425 426 @Override 427 public IWorkerContext setClientRetryCount(int value) { 428 throw new UnsupportedOperationException(Msg.code(238)); 429 } 430 431 @Override 432 public TimeTracker clock() { 433 return null; 434 } 435 436 @Override 437 public IWorkerContextManager.IPackageLoadingTracker getPackageTracker() { 438 throw new UnsupportedOperationException(Msg.code(2112)); 439 } 440 441 @Override 442 public PackageInformation getPackageForUrl(String s) { 443 return null; 444 } 445 446 public static ConceptValidationOptions convertConceptValidationOptions(ValidationOptions theOptions) { 447 ConceptValidationOptions retVal = new ConceptValidationOptions(); 448 if (theOptions.isGuessSystem()) { 449 retVal = retVal.setInferSystem(true); 450 } 451 return retVal; 452 } 453 454 @Override 455 public <T extends Resource> List<T> fetchResourcesByType(Class<T> theClass) { 456 if (theClass.equals(StructureDefinition.class)) { 457 return myValidationSupport.fetchAllStructureDefinitions(); 458 } 459 460 throw new UnsupportedOperationException(Msg.code(2113) + "Can't fetch all resources of type: " + theClass); 461 } 462 463 @Override 464 public <T extends Resource> List<T> fetchResourceVersions(Class<T> class_, String url) { 465 throw new UnsupportedOperationException(Msg.code(2827)); 466 } 467 468 @Override 469 public IWorkerContext setPackageTracker(IWorkerContextManager.IPackageLoadingTracker theIPackageLoadingTracker) { 470 throw new UnsupportedOperationException(Msg.code(220)); 471 } 472 473 @Override 474 public String getSpecUrl() { 475 return ""; 476 } 477 478 @Override 479 public PEBuilder getProfiledElementBuilder( 480 PEBuilder.PEElementPropertiesPolicy thePEElementPropertiesPolicy, boolean theB) { 481 throw new UnsupportedOperationException(Msg.code(2261)); 482 } 483 484 @Override 485 public boolean isForPublication() { 486 return false; 487 } 488 489 @Override 490 public void setForPublication(boolean b) { 491 throw new UnsupportedOperationException(Msg.code(2350)); 492 } 493 494 @Override 495 public <T extends Resource> T findTxResource( 496 Class<T> class_, String canonical, String version, Resource sourceOfReference) { 497 throw new UnsupportedOperationException(Msg.code(2829)); 498 } 499 500 @Override 501 public <T extends Resource> T findTxResource(Class<T> class_, String canonical) { 502 throw new UnsupportedOperationException(Msg.code(2492)); 503 } 504 505 @Override 506 public Boolean subsumes(ValidationOptions optionsArg, Coding parent, Coding child) { 507 throw new UnsupportedOperationException(Msg.code(2488)); 508 } 509 510 @Override 511 public OperationOutcome validateTxResource(ValidationOptions options, Resource resource) { 512 throw new UnsupportedOperationException(Msg.code(2734)); 513 } 514}