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