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