
001package org.hl7.fhir.common.hapi.validation.support; 002 003import ca.uhn.fhir.context.ConfigurationException; 004import ca.uhn.fhir.context.FhirContext; 005import ca.uhn.fhir.context.FhirVersionEnum; 006import ca.uhn.fhir.context.support.ConceptValidationOptions; 007import ca.uhn.fhir.context.support.IValidationSupport; 008import ca.uhn.fhir.context.support.LookupCodeRequest; 009import ca.uhn.fhir.context.support.ValidationSupportContext; 010import ca.uhn.fhir.i18n.Msg; 011import ca.uhn.fhir.util.ClasspathUtil; 012import ca.uhn.fhir.util.Logs; 013import ca.uhn.hapi.converters.canonical.VersionCanonicalizer; 014import com.fasterxml.jackson.core.JsonProcessingException; 015import com.fasterxml.jackson.databind.ObjectMapper; 016import com.fasterxml.jackson.databind.node.ArrayNode; 017import com.fasterxml.jackson.databind.node.ObjectNode; 018import com.google.common.annotations.VisibleForTesting; 019import jakarta.annotation.Nonnull; 020import jakarta.annotation.Nullable; 021import org.apache.commons.lang3.StringUtils; 022import org.fhir.ucum.UcumEssenceService; 023import org.fhir.ucum.UcumException; 024import org.hl7.fhir.dstu2.model.ValueSet; 025import org.hl7.fhir.instance.model.api.IBaseResource; 026import org.hl7.fhir.r4.model.CodeSystem; 027import org.hl7.fhir.r4.model.CodeSystem.CodeSystemContentMode; 028import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent; 029import org.slf4j.Logger; 030 031import java.io.IOException; 032import java.io.InputStream; 033import java.util.Collections; 034import java.util.HashMap; 035import java.util.Map; 036import java.util.Objects; 037import java.util.Optional; 038import java.util.Set; 039 040import static org.apache.commons.lang3.StringUtils.defaultString; 041import static org.apache.commons.lang3.StringUtils.isBlank; 042import static org.apache.commons.lang3.StringUtils.isNotBlank; 043 044/** 045 * This {@link IValidationSupport validation support module} can be used to validate codes against common 046 * CodeSystems that are commonly used, but are not distriuted with the FHIR specification for various reasons 047 * (size, complexity, etc.). 048 * <p> 049 * See <a href="https://hapifhir.io/hapi-fhir/docs/validation/validation_support_modules.html#CommonCodeSystemsTerminologyService">CommonCodeSystemsTerminologyService</a> in the HAPI FHIR documentation 050 * for details about what is and isn't covered by this class. 051 * </p> 052 */ 053@SuppressWarnings("EnhancedSwitchMigration") 054public class CommonCodeSystemsTerminologyService implements IValidationSupport { 055 public static final String LANGUAGES_VALUESET_URL = "http://hl7.org/fhir/ValueSet/languages"; 056 public static final String LANGUAGES_CODESYSTEM_URL = "urn:ietf:bcp:47"; 057 public static final String MIMETYPES_VALUESET_URL = "http://hl7.org/fhir/ValueSet/mimetypes"; 058 public static final String MIMETYPES_CODESYSTEM_URL = "urn:ietf:bcp:13"; 059 public static final String CURRENCIES_CODESYSTEM_URL = "urn:iso:std:iso:4217"; 060 public static final String CURRENCIES_VALUESET_URL = "http://hl7.org/fhir/ValueSet/currencies"; 061 public static final String COUNTRIES_CODESYSTEM_URL = "urn:iso:std:iso:3166"; 062 public static final String UCUM_CODESYSTEM_URL = "http://unitsofmeasure.org"; 063 public static final String UCUM_VALUESET_URL = "http://hl7.org/fhir/ValueSet/ucum-units"; 064 public static final String ALL_LANGUAGES_VALUESET_URL = "http://hl7.org/fhir/ValueSet/all-languages"; 065 public static final String USPS_CODESYSTEM_URL = "https://www.usps.com/"; 066 public static final String USPS_VALUESET_URL = "http://hl7.org/fhir/us/core/ValueSet/us-core-usps-state"; 067 private static final Logger ourLog = Logs.getTerminologyTroubleshootingLog(); 068 private static final Map<String, String> USPS_CODES = Collections.unmodifiableMap(buildUspsCodes()); 069 private static final Map<String, String> ISO_4217_CODES = Collections.unmodifiableMap(buildIso4217Codes()); 070 private static final Map<String, String> ISO_3166_CODES = Collections.unmodifiableMap(buildIso3166Codes()); 071 private final FhirContext myFhirContext; 072 private VersionCanonicalizer myVersionCanonicalizer; 073 private volatile org.hl7.fhir.r5.model.ValueSet myLanguagesVs; 074 private volatile Map<String, String> myLanguagesLanugageMap; 075 private volatile Map<String, String> myLanguagesRegionMap; 076 077 /** 078 * Constructor 079 */ 080 public CommonCodeSystemsTerminologyService(FhirContext theFhirContext) { 081 Objects.requireNonNull(theFhirContext); 082 myFhirContext = theFhirContext; 083 myVersionCanonicalizer = new VersionCanonicalizer(theFhirContext); 084 } 085 086 @VisibleForTesting 087 public void setVersionCanonicalizer(VersionCanonicalizer theVersionCanonicalizer) { 088 myVersionCanonicalizer = theVersionCanonicalizer; 089 } 090 091 @Override 092 public String getName() { 093 return myFhirContext.getVersion().getVersion() + " Common Code Systems Validation Support"; 094 } 095 096 @Override 097 public CodeValidationResult validateCodeInValueSet( 098 ValidationSupportContext theValidationSupportContext, 099 ConceptValidationOptions theOptions, 100 String theCodeSystem, 101 String theCode, 102 String theDisplay, 103 @Nonnull IBaseResource theValueSet) { 104 String url = getValueSetUrl(getFhirContext(), theValueSet); 105 return validateCode(theValidationSupportContext, theOptions, theCodeSystem, theCode, theDisplay, url); 106 } 107 108 @Override 109 public CodeValidationResult validateCode( 110 @Nonnull ValidationSupportContext theValidationSupportContext, 111 @Nonnull ConceptValidationOptions theOptions, 112 final String theCodeSystem, 113 final String theCode, 114 final String theDisplay, 115 final String theValueSetUrl) { 116 /* ************************************************************************************** 117 * NOTE: Update validation_support_modules.md if any of the support in this module 118 * changes in any way! 119 * **************************************************************************************/ 120 121 String valueSet = defaultString(theValueSetUrl); 122 String system = defaultString(theCodeSystem); 123 124 if (!isBlank(valueSet)) { 125 final String expectSystem = getCodeSystemForValueSet(valueSet); 126 if (!isBlank(system) && !system.equals(expectSystem)) { 127 return getValidateCodeResultInError("mismatchCodeSystem", system, valueSet); 128 } 129 system = expectSystem; 130 } 131 132 switch (valueSet) { 133 case USPS_VALUESET_URL: 134 return validateCodeUsingCodeMap(theCode, system, USPS_CODES); 135 case CURRENCIES_VALUESET_URL: 136 return validateCodeUsingCodeMap(theCode, system, ISO_4217_CODES); 137 case LANGUAGES_VALUESET_URL: 138 return validateLanguageCodeInValueSet(theValidationSupportContext, theCode); 139 case ALL_LANGUAGES_VALUESET_URL: 140 return validateLanguageCode(theCode, valueSet); 141 case MIMETYPES_VALUESET_URL: 142 // This is a pretty naive implementation - Should be enhanced in future 143 return getValidateCodeResultOk(theCode, theDisplay); 144 case UCUM_VALUESET_URL: { 145 return validateCodeUsingSystemLookup(theValidationSupportContext, theCode, system); 146 } 147 } 148 149 if (isBlank(valueSet)) { 150 return validateCodeUsingSystemLookup(theValidationSupportContext, theCode, system); 151 } 152 153 return null; 154 } 155 156 private static String getCodeSystemForValueSet(final String theValueSetUrl) { 157 String theCodeSystem = null; 158 switch (defaultString(theValueSetUrl)) { 159 case USPS_VALUESET_URL: 160 theCodeSystem = USPS_CODESYSTEM_URL; 161 break; 162 case CURRENCIES_VALUESET_URL: 163 theCodeSystem = CURRENCIES_CODESYSTEM_URL; 164 break; 165 case LANGUAGES_VALUESET_URL: 166 case ALL_LANGUAGES_VALUESET_URL: 167 theCodeSystem = LANGUAGES_CODESYSTEM_URL; 168 break; 169 case MIMETYPES_VALUESET_URL: 170 theCodeSystem = MIMETYPES_CODESYSTEM_URL; 171 break; 172 case UCUM_VALUESET_URL: 173 theCodeSystem = UCUM_CODESYSTEM_URL; 174 break; 175 } 176 return theCodeSystem; 177 } 178 179 protected CodeValidationResult getValidateCodeResultInError( 180 final String errorCode, final String theFirstParam, final String theSecondParam) { 181 String message = getErrorMessage(errorCode, theFirstParam, theSecondParam); 182 return getValidateCodeResultError(message); 183 } 184 185 protected CodeValidationResult getValidateCodeResultOk(final String theCode, final String theDisplay) { 186 return new CodeValidationResult().setCode(theCode).setDisplay(theDisplay); 187 } 188 189 protected CodeValidationResult getValidateCodeResultError(final String theMessage) { 190 return new CodeValidationResult() 191 .setSeverity(IssueSeverity.ERROR) 192 .setMessage(theMessage) 193 .setIssues(Collections.singletonList(new CodeValidationIssue( 194 theMessage, 195 IssueSeverity.ERROR, 196 CodeValidationIssueCode.INVALID, 197 CodeValidationIssueCoding.INVALID_CODE))); 198 } 199 200 private CodeValidationResult validateCodeUsingCodeMap( 201 final String theCode, final String theSystem, final Map<String, String> theCodeMap) { 202 if (theCodeMap.containsKey(theCode)) { 203 return getValidateCodeResultOk(theCode, theCodeMap.get(theCode)); 204 } else { 205 return getValidateCodeResultInError("unknownCodeInSystem", theSystem, theCode); 206 } 207 } 208 209 @Nullable 210 public CodeValidationResult validateCodeUsingSystemLookup( 211 final ValidationSupportContext theValidationSupportContext, final String theCode, final String theSystem) { 212 LookupCodeResult result = lookupCode(theValidationSupportContext, new LookupCodeRequest(theSystem, theCode)); 213 if (result == null) { 214 return getValidateCodeResultInError("unknownCodeInSystem", theSystem, theCode); 215 } 216 if (result.isFound()) { 217 return getValidateCodeResultOk(theCode, result.getCodeDisplay()); 218 } else if (result.getErrorMessage() != null) { 219 String errorMessageWithSystemInfo = result.getErrorMessage() + " (for '" + theSystem + "#" + theCode + "')"; 220 return getValidateCodeResultError(errorMessageWithSystemInfo); 221 } 222 return null; 223 } 224 225 @Override 226 public LookupCodeResult lookupCode( 227 ValidationSupportContext theValidationSupportContext, @Nonnull LookupCodeRequest theLookupCodeRequest) { 228 final String code = theLookupCodeRequest.getCode(); 229 final String system = theLookupCodeRequest.getSystem(); 230 231 Map<String, String> map; 232 switch (system) { 233 case LANGUAGES_CODESYSTEM_URL: 234 return lookupLanguageCode(code); 235 case UCUM_CODESYSTEM_URL: 236 return lookupUcumCode(code); 237 case MIMETYPES_CODESYSTEM_URL: 238 return lookupMimetypeCode(code); 239 case COUNTRIES_CODESYSTEM_URL: 240 map = ISO_3166_CODES; 241 break; 242 case CURRENCIES_CODESYSTEM_URL: 243 map = ISO_4217_CODES; 244 break; 245 case USPS_CODESYSTEM_URL: 246 map = USPS_CODES; 247 break; 248 default: 249 return null; 250 } 251 252 LookupCodeResult retVal = new LookupCodeResult(); 253 retVal.setSearchedForCode(code); 254 retVal.setSearchedForSystem(system); 255 256 String display = map.get(code); 257 if (isNotBlank(display)) { 258 retVal.setFound(true); 259 retVal.setCodeDisplay(display); 260 } else { 261 // If we get here it means we know the CodeSystem but the code was bad 262 retVal.setFound(false); 263 String invalidCodeMessage = getErrorMessage("invalidCodeInSystem", code, system); 264 retVal.setErrorMessage(invalidCodeMessage); 265 } 266 267 return retVal; 268 } 269 270 private CodeValidationResult validateLanguageCode(final String theCode, final String theValueSetUrl) { 271 LookupCodeResult outcome = lookupLanguageCode(theCode); 272 if (outcome.isFound()) { 273 return getValidateCodeResultOk(theCode, outcome.getCodeDisplay()); 274 } else { 275 return getValidateCodeResultInError("codeNotFoundInValueSet", theCode, theValueSetUrl); 276 } 277 } 278 279 private CodeValidationResult validateLanguageCodeInValueSet( 280 final ValidationSupportContext theValidationSupportContext, final String theCode) { 281 final String valueSet = LANGUAGES_VALUESET_URL; 282 if (myLanguagesVs == null) { 283 IBaseResource languagesVs = 284 theValidationSupportContext.getRootValidationSupport().fetchValueSet(valueSet); 285 myLanguagesVs = myVersionCanonicalizer.valueSetToValidatorCanonical(languagesVs); 286 } 287 Optional<ConceptReferenceComponent> match = myLanguagesVs.getCompose().getInclude().stream() 288 .flatMap(t -> t.getConcept().stream()) 289 .filter(t -> theCode.equals(t.getCode())) 290 .findFirst(); 291 if (match.isPresent()) { 292 return getValidateCodeResultOk(theCode, match.get().getDisplay()); 293 } else { 294 return getValidateCodeResultInError("codeNotFoundInValueSet", theCode, valueSet); 295 } 296 } 297 298 private LookupCodeResult lookupLanguageCode(String theCode) { 299 if (myLanguagesLanugageMap == null || myLanguagesRegionMap == null) { 300 initializeBcp47LanguageMap(); 301 } 302 303 final LookupCodeResult lookupCodeResult = new LookupCodeResult(); 304 lookupCodeResult.setSearchedForSystem(LANGUAGES_CODESYSTEM_URL); 305 lookupCodeResult.setSearchedForCode(theCode); 306 307 final int langRegionSeparatorIndex = StringUtils.indexOfAny(theCode, '-', '_'); 308 final boolean hasRegionAndCodeSegments = langRegionSeparatorIndex > 0; 309 310 final boolean found; 311 final String display; 312 313 if (hasRegionAndCodeSegments) { 314 // we look for languages in lowercase only 315 // this will allow case insensitivity for language portion of code 316 String language = myLanguagesLanugageMap.get( 317 theCode.substring(0, langRegionSeparatorIndex).toLowerCase()); 318 String region = myLanguagesRegionMap.get( 319 theCode.substring(langRegionSeparatorIndex + 1).toUpperCase()); 320 321 // In case the user provides both a language and a region, they must both be valid for the lookup to 322 // succeed. 323 found = language != null && region != null; 324 display = found ? language + " " + region : null; 325 if (!found) { 326 ourLog.warn("Couldn't find a valid bcp47 language-region combination from code: {}", theCode); 327 } 328 } else { 329 // In case user has only provided a language, we build the lookup from only that. 330 // NB: we only use the lowercase version of the language 331 String language = myLanguagesLanugageMap.get(theCode.toLowerCase()); 332 found = language != null; 333 display = language; 334 if (!found) { 335 ourLog.warn("Couldn't find a valid bcp47 language from code: {}", theCode); 336 } 337 } 338 339 lookupCodeResult.setFound(found); 340 lookupCodeResult.setCodeDisplay(display); 341 342 return lookupCodeResult; 343 } 344 345 private void initializeBcp47LanguageMap() { 346 Map<String, String> regionsMap; 347 Map<String, String> languagesMap; 348 ourLog.info("Loading BCP47 Language Registry"); 349 350 String input = ClasspathUtil.loadResource("org/hl7/fhir/common/hapi/validation/support/registry.json"); 351 ArrayNode map; 352 try { 353 map = (ArrayNode) new ObjectMapper().readTree(input); 354 } catch (JsonProcessingException e) { 355 throw new ConfigurationException(Msg.code(694) + e); 356 } 357 358 languagesMap = new HashMap<>(); 359 regionsMap = new HashMap<>(); 360 361 for (int i = 0; i < map.size(); i++) { 362 ObjectNode next = (ObjectNode) map.get(i); 363 String type = next.get("Type").asText(); 364 if ("language".equals(type)) { 365 populateSubTagMap(languagesMap, next); 366 } 367 if ("region".equals(type)) { 368 populateSubTagMap(regionsMap, next); 369 } 370 } 371 372 ourLog.info("Have {} languages and {} regions", languagesMap.size(), regionsMap.size()); 373 374 myLanguagesLanugageMap = languagesMap; 375 myLanguagesRegionMap = regionsMap; 376 } 377 378 private void populateSubTagMap(Map<String, String> theLanguagesMap, ObjectNode theNext) { 379 String language = theNext.get("Subtag").asText(); 380 ArrayNode descriptions = (ArrayNode) theNext.get("Description"); 381 String description = null; 382 if (!descriptions.isEmpty()) { 383 description = descriptions.get(0).asText(); 384 } 385 theLanguagesMap.put(language, description); 386 } 387 388 @Nonnull 389 private LookupCodeResult lookupMimetypeCode(String theCode) { 390 // This is a pretty naive implementation - Should be enhanced in future 391 LookupCodeResult mimeRetVal = new LookupCodeResult(); 392 mimeRetVal.setSearchedForCode(theCode); 393 mimeRetVal.setSearchedForSystem(MIMETYPES_CODESYSTEM_URL); 394 mimeRetVal.setFound(true); 395 return mimeRetVal; 396 } 397 398 @Nonnull 399 private LookupCodeResult lookupUcumCode(String theCode) { 400 LookupCodeResult retVal = new LookupCodeResult(); 401 retVal.setSearchedForCode(theCode); 402 retVal.setSearchedForSystem(UCUM_CODESYSTEM_URL); 403 404 try (InputStream input = ClasspathUtil.loadResourceAsStream("/ucum-essence.xml")) { 405 UcumEssenceService svc = new UcumEssenceService(input); 406 String outcome = svc.analyse(theCode); 407 if (outcome != null) { 408 retVal.setFound(true); 409 retVal.setCodeDisplay(outcome); 410 } 411 } catch (UcumException | IOException e) { 412 ourLog.debug("Failed parse UCUM code: {}", theCode, e); 413 retVal.setErrorMessage(e.getMessage()); 414 } 415 return retVal; 416 } 417 418 @Override 419 public IBaseResource fetchCodeSystem(String theSystem) { 420 final CodeSystemContentMode content; 421 Map<String, String> map; 422 switch (defaultString(theSystem)) { 423 case COUNTRIES_CODESYSTEM_URL: 424 map = ISO_3166_CODES; 425 content = CodeSystemContentMode.COMPLETE; 426 break; 427 case CURRENCIES_CODESYSTEM_URL: 428 map = ISO_4217_CODES; 429 content = CodeSystemContentMode.COMPLETE; 430 break; 431 case MIMETYPES_CODESYSTEM_URL: 432 map = Collections.emptyMap(); 433 content = CodeSystemContentMode.NOTPRESENT; 434 break; 435 default: 436 return null; 437 } 438 439 CodeSystem retVal = new CodeSystem(); 440 retVal.setContent(content); 441 retVal.setUrl(theSystem); 442 for (Map.Entry<String, String> nextEntry : map.entrySet()) { 443 retVal.addConcept().setCode(nextEntry.getKey()).setDisplay(nextEntry.getValue()); 444 } 445 446 IBaseResource normalized = myVersionCanonicalizer.codeSystemFromCanonical(retVal); 447 Set<FhirVersionEnum> nullableVersions = 448 Set.of(FhirVersionEnum.DSTU2, FhirVersionEnum.DSTU2_HL7ORG, FhirVersionEnum.DSTU2_1); 449 boolean isNullableVersion = 450 nullableVersions.contains(getFhirContext().getVersion().getVersion()); 451 if (!isNullableVersion) { 452 Objects.requireNonNull(normalized); 453 } 454 455 return normalized; 456 } 457 458 @Override 459 public boolean isCodeSystemSupported(ValidationSupportContext theValidationSupportContext, String theSystem) { 460 if (theSystem == null) { 461 return false; 462 } 463 switch (theSystem) { 464 case COUNTRIES_CODESYSTEM_URL: 465 case UCUM_CODESYSTEM_URL: 466 case MIMETYPES_CODESYSTEM_URL: 467 case USPS_CODESYSTEM_URL: 468 case LANGUAGES_CODESYSTEM_URL: 469 return true; 470 } 471 472 return false; 473 } 474 475 @Override 476 public boolean isValueSetSupported(ValidationSupportContext theValidationSupportContext, String theValueSetUrl) { 477 478 switch (theValueSetUrl) { 479 case CURRENCIES_VALUESET_URL: 480 case LANGUAGES_VALUESET_URL: 481 case ALL_LANGUAGES_VALUESET_URL: 482 case MIMETYPES_VALUESET_URL: 483 case UCUM_VALUESET_URL: 484 case USPS_VALUESET_URL: 485 return true; 486 } 487 488 return false; 489 } 490 491 @Override 492 public FhirContext getFhirContext() { 493 return myFhirContext; 494 } 495 496 public static String getValueSetUrl(FhirContext theFhirContext, @Nonnull IBaseResource theValueSet) { 497 String url; 498 FhirVersionEnum structureFhirVersionEnum = getFhirVersionEnum(theFhirContext, theValueSet); 499 switch (structureFhirVersionEnum) { 500 case DSTU2: { 501 url = ((ca.uhn.fhir.model.dstu2.resource.ValueSet) theValueSet).getUrl(); 502 break; 503 } 504 case DSTU2_HL7ORG: { 505 url = ((ValueSet) theValueSet).getUrl(); 506 break; 507 } 508 case DSTU3: { 509 url = ((org.hl7.fhir.dstu3.model.ValueSet) theValueSet).getUrl(); 510 break; 511 } 512 case R4: { 513 url = ((org.hl7.fhir.r4.model.ValueSet) theValueSet).getUrl(); 514 break; 515 } 516 case R4B: { 517 url = ((org.hl7.fhir.r4b.model.ValueSet) theValueSet).getUrl(); 518 break; 519 } 520 case R5: { 521 url = ((org.hl7.fhir.r5.model.ValueSet) theValueSet).getUrl(); 522 break; 523 } 524 case DSTU2_1: 525 default: 526 throw new IllegalArgumentException( 527 Msg.code(695) + "Can not handle version: " + structureFhirVersionEnum); 528 } 529 return url; 530 } 531 532 public static String getCodeSystemUrl(@Nonnull FhirContext theFhirContext, @Nonnull IBaseResource theCodeSystem) { 533 String url; 534 FhirVersionEnum structureFhirVersionEnum = getFhirVersionEnum(theFhirContext, theCodeSystem); 535 switch (structureFhirVersionEnum) { 536 case R4: { 537 url = ((org.hl7.fhir.r4.model.CodeSystem) theCodeSystem).getUrl(); 538 break; 539 } 540 case R4B: { 541 url = ((org.hl7.fhir.r4b.model.CodeSystem) theCodeSystem).getUrl(); 542 break; 543 } 544 case R5: { 545 url = ((org.hl7.fhir.r5.model.CodeSystem) theCodeSystem).getUrl(); 546 break; 547 } 548 case DSTU3: 549 default: 550 throw new IllegalArgumentException( 551 Msg.code(696) + "Can not handle version: " + structureFhirVersionEnum); 552 } 553 return url; 554 } 555 556 public static String getValueSetVersion(@Nonnull FhirContext theFhirContext, @Nonnull IBaseResource theValueSet) { 557 String version; 558 switch (getFhirVersionEnum(theFhirContext, theValueSet)) { 559 case DSTU3: { 560 version = ((org.hl7.fhir.dstu3.model.ValueSet) theValueSet).getVersion(); 561 break; 562 } 563 case R4: { 564 version = ((org.hl7.fhir.r4.model.ValueSet) theValueSet).getVersion(); 565 break; 566 } 567 case R4B: { 568 version = ((org.hl7.fhir.r4b.model.ValueSet) theValueSet).getVersion(); 569 break; 570 } 571 case R5: { 572 version = ((org.hl7.fhir.r5.model.ValueSet) theValueSet).getVersion(); 573 break; 574 } 575 case DSTU2: 576 case DSTU2_HL7ORG: 577 case DSTU2_1: 578 default: 579 version = null; 580 } 581 return version; 582 } 583 584 /** 585 * N.B.: We are keeping this as a shim due to the upgrade we did to core 5.6.97+ 586 */ 587 public static FhirVersionEnum getFhirVersionEnum( 588 @Nonnull FhirContext theFhirContext, @Nonnull IBaseResource theResource) { 589 FhirVersionEnum structureFhirVersionEnum = theResource.getStructureFhirVersionEnum(); 590 // TODO: Address this when core lib version is bumped 591 if (theResource.getStructureFhirVersionEnum() == FhirVersionEnum.R5 592 && theFhirContext.getVersion().getVersion() == FhirVersionEnum.R4B) { 593 if (!(theResource instanceof org.hl7.fhir.r5.model.Resource)) { 594 structureFhirVersionEnum = FhirVersionEnum.R4B; 595 } 596 } 597 return structureFhirVersionEnum; 598 } 599 600 private static HashMap<String, String> buildUspsCodes() { 601 HashMap<String, String> uspsCodes = new HashMap<>(); 602 uspsCodes.put("AK", "Alaska"); 603 uspsCodes.put("AL", "Alabama"); 604 uspsCodes.put("AR", "Arkansas"); 605 uspsCodes.put("AS", "American Samoa"); 606 uspsCodes.put("AZ", "Arizona"); 607 uspsCodes.put("CA", "California"); 608 uspsCodes.put("CO", "Colorado"); 609 uspsCodes.put("CT", "Connecticut"); 610 uspsCodes.put("DC", "District of Columbia"); 611 uspsCodes.put("DE", "Delaware"); 612 uspsCodes.put("FL", "Florida"); 613 uspsCodes.put("FM", "Federated States of Micronesia"); 614 uspsCodes.put("GA", "Georgia"); 615 uspsCodes.put("GU", "Guam"); 616 uspsCodes.put("HI", "Hawaii"); 617 uspsCodes.put("IA", "Iowa"); 618 uspsCodes.put("ID", "Idaho"); 619 uspsCodes.put("IL", "Illinois"); 620 uspsCodes.put("IN", "Indiana"); 621 uspsCodes.put("KS", "Kansas"); 622 uspsCodes.put("KY", "Kentucky"); 623 uspsCodes.put("LA", "Louisiana"); 624 uspsCodes.put("MA", "Massachusetts"); 625 uspsCodes.put("MD", "Maryland"); 626 uspsCodes.put("ME", "Maine"); 627 uspsCodes.put("MH", "Marshall Islands"); 628 uspsCodes.put("MI", "Michigan"); 629 uspsCodes.put("MN", "Minnesota"); 630 uspsCodes.put("MO", "Missouri"); 631 uspsCodes.put("MP", "Northern Mariana Islands"); 632 uspsCodes.put("MS", "Mississippi"); 633 uspsCodes.put("MT", "Montana"); 634 uspsCodes.put("NC", "North Carolina"); 635 uspsCodes.put("ND", "North Dakota"); 636 uspsCodes.put("NE", "Nebraska"); 637 uspsCodes.put("NH", "New Hampshire"); 638 uspsCodes.put("NJ", "New Jersey"); 639 uspsCodes.put("NM", "New Mexico"); 640 uspsCodes.put("NV", "Nevada"); 641 uspsCodes.put("NY", "New York"); 642 uspsCodes.put("OH", "Ohio"); 643 uspsCodes.put("OK", "Oklahoma"); 644 uspsCodes.put("OR", "Oregon"); 645 uspsCodes.put("PA", "Pennsylvania"); 646 uspsCodes.put("PR", "Puerto Rico"); 647 uspsCodes.put("PW", "Palau"); 648 uspsCodes.put("RI", "Rhode Island"); 649 uspsCodes.put("SC", "South Carolina"); 650 uspsCodes.put("SD", "South Dakota"); 651 uspsCodes.put("TN", "Tennessee"); 652 uspsCodes.put("TX", "Texas"); 653 uspsCodes.put("UM", "U.S. Minor Outlying Islands"); 654 uspsCodes.put("UT", "Utah"); 655 uspsCodes.put("VA", "Virginia"); 656 uspsCodes.put("VI", "Virgin Islands of the U.S."); 657 uspsCodes.put("VT", "Vermont"); 658 uspsCodes.put("WA", "Washington"); 659 uspsCodes.put("WI", "Wisconsin"); 660 uspsCodes.put("WV", "West Virginia"); 661 uspsCodes.put("WY", "Wyoming"); 662 return uspsCodes; 663 } 664 665 private static HashMap<String, String> buildIso4217Codes() { 666 HashMap<String, String> iso4217Codes = new HashMap<>(); 667 iso4217Codes.put("AED", "United Arab Emirates dirham"); 668 iso4217Codes.put("AFN", "Afghan afghani"); 669 iso4217Codes.put("ALL", "Albanian lek"); 670 iso4217Codes.put("AMD", "Armenian dram"); 671 iso4217Codes.put("ANG", "Netherlands Antillean guilder"); 672 iso4217Codes.put("AOA", "Angolan kwanza"); 673 iso4217Codes.put("ARS", "Argentine peso"); 674 iso4217Codes.put("AUD", "Australian dollar"); 675 iso4217Codes.put("AWG", "Aruban florin"); 676 iso4217Codes.put("AZN", "Azerbaijani manat"); 677 iso4217Codes.put("BAM", "Bosnia and Herzegovina convertible mark"); 678 iso4217Codes.put("BBD", "Barbados dollar"); 679 iso4217Codes.put("BDT", "Bangladeshi taka"); 680 iso4217Codes.put("BGN", "Bulgarian lev"); 681 iso4217Codes.put("BHD", "Bahraini dinar"); 682 iso4217Codes.put("BIF", "Burundian franc"); 683 iso4217Codes.put("BMD", "Bermudian dollar"); 684 iso4217Codes.put("BND", "Brunei dollar"); 685 iso4217Codes.put("BOB", "Boliviano"); 686 iso4217Codes.put("BOV", "Bolivian Mvdol (funds code)"); 687 iso4217Codes.put("BRL", "Brazilian real"); 688 iso4217Codes.put("BSD", "Bahamian dollar"); 689 iso4217Codes.put("BTN", "Bhutanese ngultrum"); 690 iso4217Codes.put("BWP", "Botswana pula"); 691 iso4217Codes.put("BYN", "Belarusian ruble"); 692 iso4217Codes.put("BZD", "Belize dollar"); 693 iso4217Codes.put("CAD", "Canadian dollar"); 694 iso4217Codes.put("CDF", "Congolese franc"); 695 iso4217Codes.put("CHE", "WIR Euro (complementary currency)"); 696 iso4217Codes.put("CHF", "Swiss franc"); 697 iso4217Codes.put("CHW", "WIR Franc (complementary currency)"); 698 iso4217Codes.put("CLF", "Unidad de Fomento (funds code)"); 699 iso4217Codes.put("CLP", "Chilean peso"); 700 iso4217Codes.put("CNY", "Renminbi (Chinese) yuan[8]"); 701 iso4217Codes.put("COP", "Colombian peso"); 702 iso4217Codes.put("COU", "Unidad de Valor Real (UVR) (funds code)[9]"); 703 iso4217Codes.put("CRC", "Costa Rican colon"); 704 iso4217Codes.put("CUC", "Cuban convertible peso"); 705 iso4217Codes.put("CUP", "Cuban peso"); 706 iso4217Codes.put("CVE", "Cape Verde escudo"); 707 iso4217Codes.put("CZK", "Czech koruna"); 708 iso4217Codes.put("DJF", "Djiboutian franc"); 709 iso4217Codes.put("DKK", "Danish krone"); 710 iso4217Codes.put("DOP", "Dominican peso"); 711 iso4217Codes.put("DZD", "Algerian dinar"); 712 iso4217Codes.put("EGP", "Egyptian pound"); 713 iso4217Codes.put("ERN", "Eritrean nakfa"); 714 iso4217Codes.put("ETB", "Ethiopian birr"); 715 iso4217Codes.put("EUR", "Euro"); 716 iso4217Codes.put("FJD", "Fiji dollar"); 717 iso4217Codes.put("FKP", "Falkland Islands pound"); 718 iso4217Codes.put("GBP", "Pound sterling"); 719 iso4217Codes.put("GEL", "Georgian lari"); 720 iso4217Codes.put("GGP", "Guernsey Pound"); 721 iso4217Codes.put("GHS", "Ghanaian cedi"); 722 iso4217Codes.put("GIP", "Gibraltar pound"); 723 iso4217Codes.put("GMD", "Gambian dalasi"); 724 iso4217Codes.put("GNF", "Guinean franc"); 725 iso4217Codes.put("GTQ", "Guatemalan quetzal"); 726 iso4217Codes.put("GYD", "Guyanese dollar"); 727 iso4217Codes.put("HKD", "Hong Kong dollar"); 728 iso4217Codes.put("HNL", "Honduran lempira"); 729 iso4217Codes.put("HRK", "Croatian kuna"); 730 iso4217Codes.put("HTG", "Haitian gourde"); 731 iso4217Codes.put("HUF", "Hungarian forint"); 732 iso4217Codes.put("IDR", "Indonesian rupiah"); 733 iso4217Codes.put("ILS", "Israeli new shekel"); 734 iso4217Codes.put("IMP", "Isle of Man Pound"); 735 iso4217Codes.put("INR", "Indian rupee"); 736 iso4217Codes.put("IQD", "Iraqi dinar"); 737 iso4217Codes.put("IRR", "Iranian rial"); 738 iso4217Codes.put("ISK", "Icelandic króna"); 739 iso4217Codes.put("JEP", "Jersey Pound"); 740 iso4217Codes.put("JMD", "Jamaican dollar"); 741 iso4217Codes.put("JOD", "Jordanian dinar"); 742 iso4217Codes.put("JPY", "Japanese yen"); 743 iso4217Codes.put("KES", "Kenyan shilling"); 744 iso4217Codes.put("KGS", "Kyrgyzstani som"); 745 iso4217Codes.put("KHR", "Cambodian riel"); 746 iso4217Codes.put("KMF", "Comoro franc"); 747 iso4217Codes.put("KPW", "North Korean won"); 748 iso4217Codes.put("KRW", "South Korean won"); 749 iso4217Codes.put("KWD", "Kuwaiti dinar"); 750 iso4217Codes.put("KYD", "Cayman Islands dollar"); 751 iso4217Codes.put("KZT", "Kazakhstani tenge"); 752 iso4217Codes.put("LAK", "Lao kip"); 753 iso4217Codes.put("LBP", "Lebanese pound"); 754 iso4217Codes.put("LKR", "Sri Lankan rupee"); 755 iso4217Codes.put("LRD", "Liberian dollar"); 756 iso4217Codes.put("LSL", "Lesotho loti"); 757 iso4217Codes.put("LYD", "Libyan dinar"); 758 iso4217Codes.put("MAD", "Moroccan dirham"); 759 iso4217Codes.put("MDL", "Moldovan leu"); 760 iso4217Codes.put("MGA", "Malagasy ariary"); 761 iso4217Codes.put("MKD", "Macedonian denar"); 762 iso4217Codes.put("MMK", "Myanmar kyat"); 763 iso4217Codes.put("MNT", "Mongolian tögrög"); 764 iso4217Codes.put("MOP", "Macanese pataca"); 765 iso4217Codes.put("MRU", "Mauritanian ouguiya"); 766 iso4217Codes.put("MUR", "Mauritian rupee"); 767 iso4217Codes.put("MVR", "Maldivian rufiyaa"); 768 iso4217Codes.put("MWK", "Malawian kwacha"); 769 iso4217Codes.put("MXN", "Mexican peso"); 770 iso4217Codes.put("MXV", "Mexican Unidad de Inversion (UDI) (funds code)"); 771 iso4217Codes.put("MYR", "Malaysian ringgit"); 772 iso4217Codes.put("MZN", "Mozambican metical"); 773 iso4217Codes.put("NAD", "Namibian dollar"); 774 iso4217Codes.put("NGN", "Nigerian naira"); 775 iso4217Codes.put("NIO", "Nicaraguan córdoba"); 776 iso4217Codes.put("NOK", "Norwegian krone"); 777 iso4217Codes.put("NPR", "Nepalese rupee"); 778 iso4217Codes.put("NZD", "New Zealand dollar"); 779 iso4217Codes.put("OMR", "Omani rial"); 780 iso4217Codes.put("PAB", "Panamanian balboa"); 781 iso4217Codes.put("PEN", "Peruvian Sol"); 782 iso4217Codes.put("PGK", "Papua New Guinean kina"); 783 iso4217Codes.put("PHP", "Philippine piso[13]"); 784 iso4217Codes.put("PKR", "Pakistani rupee"); 785 iso4217Codes.put("PLN", "Polish z?oty"); 786 iso4217Codes.put("PYG", "Paraguayan guaraní"); 787 iso4217Codes.put("QAR", "Qatari riyal"); 788 iso4217Codes.put("RON", "Romanian leu"); 789 iso4217Codes.put("RSD", "Serbian dinar"); 790 iso4217Codes.put("RUB", "Russian ruble"); 791 iso4217Codes.put("RWF", "Rwandan franc"); 792 iso4217Codes.put("SAR", "Saudi riyal"); 793 iso4217Codes.put("SBD", "Solomon Islands dollar"); 794 iso4217Codes.put("SCR", "Seychelles rupee"); 795 iso4217Codes.put("SDG", "Sudanese pound"); 796 iso4217Codes.put("SEK", "Swedish krona/kronor"); 797 iso4217Codes.put("SGD", "Singapore dollar"); 798 iso4217Codes.put("SHP", "Saint Helena pound"); 799 iso4217Codes.put("SLL", "Sierra Leonean leone"); 800 iso4217Codes.put("SOS", "Somali shilling"); 801 iso4217Codes.put("SRD", "Surinamese dollar"); 802 iso4217Codes.put("SSP", "South Sudanese pound"); 803 iso4217Codes.put("STN", "São Tomé and Príncipe dobra"); 804 iso4217Codes.put("SVC", "Salvadoran colón"); 805 iso4217Codes.put("SYP", "Syrian pound"); 806 iso4217Codes.put("SZL", "Swazi lilangeni"); 807 iso4217Codes.put("THB", "Thai baht"); 808 iso4217Codes.put("TJS", "Tajikistani somoni"); 809 iso4217Codes.put("TMT", "Turkmenistan manat"); 810 iso4217Codes.put("TND", "Tunisian dinar"); 811 iso4217Codes.put("TOP", "Tongan pa?anga"); 812 iso4217Codes.put("TRY", "Turkish lira"); 813 iso4217Codes.put("TTD", "Trinidad and Tobago dollar"); 814 iso4217Codes.put("TVD", "Tuvalu Dollar"); 815 iso4217Codes.put("TWD", "New Taiwan dollar"); 816 iso4217Codes.put("TZS", "Tanzanian shilling"); 817 iso4217Codes.put("UAH", "Ukrainian hryvnia"); 818 iso4217Codes.put("UGX", "Ugandan shilling"); 819 iso4217Codes.put("USD", "United States dollar"); 820 iso4217Codes.put("USN", "United States dollar (next day) (funds code)"); 821 iso4217Codes.put("UYI", "Uruguay Peso en Unidades Indexadas (URUIURUI) (funds code)"); 822 iso4217Codes.put("UYU", "Uruguayan peso"); 823 iso4217Codes.put("UZS", "Uzbekistan som"); 824 iso4217Codes.put("VEF", "Venezuelan bolívar"); 825 iso4217Codes.put("VND", "Vietnamese ??ng"); 826 iso4217Codes.put("VUV", "Vanuatu vatu"); 827 iso4217Codes.put("WST", "Samoan tala"); 828 iso4217Codes.put("XAF", "CFA franc BEAC"); 829 iso4217Codes.put("XAG", "Silver (one troy ounce)"); 830 iso4217Codes.put("XAU", "Gold (one troy ounce)"); 831 iso4217Codes.put("XBA", "European Composite Unit (EURCO) (bond market unit)"); 832 iso4217Codes.put("XBB", "European Monetary Unit (E.M.U.-6) (bond market unit)"); 833 iso4217Codes.put("XBC", "European Unit of Account 9 (E.U.A.-9) (bond market unit)"); 834 iso4217Codes.put("XBD", "European Unit of Account 17 (E.U.A.-17) (bond market unit)"); 835 iso4217Codes.put("XCD", "East Caribbean dollar"); 836 iso4217Codes.put("XDR", "Special drawing rights"); 837 iso4217Codes.put("XOF", "CFA franc BCEAO"); 838 iso4217Codes.put("XPD", "Palladium (one troy ounce)"); 839 iso4217Codes.put("XPF", "CFP franc (franc Pacifique)"); 840 iso4217Codes.put("XPT", "Platinum (one troy ounce)"); 841 iso4217Codes.put("XSU", "SUCRE"); 842 iso4217Codes.put("XTS", "Code reserved for testing purposes"); 843 iso4217Codes.put("XUA", "ADB Unit of Account"); 844 iso4217Codes.put("XXX", "No currency"); 845 iso4217Codes.put("YER", "Yemeni rial"); 846 iso4217Codes.put("ZAR", "South African rand"); 847 iso4217Codes.put("ZMW", "Zambian kwacha"); 848 iso4217Codes.put("ZWL", "Zimbabwean dollar A/10"); 849 return iso4217Codes; 850 } 851 852 private static HashMap<String, String> buildIso3166Codes() { 853 HashMap<String, String> codes = new HashMap<>(); 854 855 // 2 letter codes 856 codes.put("AF", "Afghanistan"); 857 codes.put("AX", "Åland Islands"); 858 codes.put("AL", "Albania"); 859 codes.put("DZ", "Algeria"); 860 codes.put("AS", "American Samoa"); 861 codes.put("AD", "Andorra"); 862 codes.put("AO", "Angola"); 863 codes.put("AI", "Anguilla"); 864 codes.put("AQ", "Antarctica"); 865 codes.put("AG", "Antigua & Barbuda"); 866 codes.put("AR", "Argentina"); 867 codes.put("AM", "Armenia"); 868 codes.put("AW", "Aruba"); 869 codes.put("AU", "Australia"); 870 codes.put("AT", "Austria"); 871 codes.put("AZ", "Azerbaijan"); 872 codes.put("BS", "Bahamas"); 873 codes.put("BH", "Bahrain"); 874 codes.put("BD", "Bangladesh"); 875 codes.put("BB", "Barbados"); 876 codes.put("BY", "Belarus"); 877 codes.put("BE", "Belgium"); 878 codes.put("BZ", "Belize"); 879 codes.put("BJ", "Benin"); 880 codes.put("BM", "Bermuda"); 881 codes.put("BT", "Bhutan"); 882 codes.put("BO", "Bolivia"); 883 codes.put("BA", "Bosnia & Herzegovina"); 884 codes.put("BW", "Botswana"); 885 codes.put("BV", "Bouvet Island"); 886 codes.put("BR", "Brazil"); 887 codes.put("IO", "British Indian Ocean Territory"); 888 codes.put("VG", "British Virgin Islands"); 889 codes.put("BN", "Brunei"); 890 codes.put("BG", "Bulgaria"); 891 codes.put("BF", "Burkina Faso"); 892 codes.put("BI", "Burundi"); 893 codes.put("KH", "Cambodia"); 894 codes.put("CM", "Cameroon"); 895 codes.put("CA", "Canada"); 896 codes.put("CV", "Cape Verde"); 897 codes.put("BQ", "Caribbean Netherlands"); 898 codes.put("KY", "Cayman Islands"); 899 codes.put("CF", "Central African Republic"); 900 codes.put("TD", "Chad"); 901 codes.put("CL", "Chile"); 902 codes.put("CN", "China"); 903 codes.put("CX", "Christmas Island"); 904 codes.put("CC", "Cocos (Keeling) Islands"); 905 codes.put("CO", "Colombia"); 906 codes.put("KM", "Comoros"); 907 codes.put("CG", "Congo - Brazzaville"); 908 codes.put("CD", "Congo - Kinshasa"); 909 codes.put("CK", "Cook Islands"); 910 codes.put("CR", "Costa Rica"); 911 codes.put("CI", "Côte d?Ivoire"); 912 codes.put("HR", "Croatia"); 913 codes.put("CU", "Cuba"); 914 codes.put("CW", "Curaçao"); 915 codes.put("CY", "Cyprus"); 916 codes.put("CZ", "Czechia"); 917 codes.put("DK", "Denmark"); 918 codes.put("DJ", "Djibouti"); 919 codes.put("DM", "Dominica"); 920 codes.put("DO", "Dominican Republic"); 921 codes.put("EC", "Ecuador"); 922 codes.put("EG", "Egypt"); 923 codes.put("SV", "El Salvador"); 924 codes.put("GQ", "Equatorial Guinea"); 925 codes.put("ER", "Eritrea"); 926 codes.put("EE", "Estonia"); 927 codes.put("SZ", "Eswatini"); 928 codes.put("ET", "Ethiopia"); 929 codes.put("FK", "Falkland Islands"); 930 codes.put("FO", "Faroe Islands"); 931 codes.put("FJ", "Fiji"); 932 codes.put("FI", "Finland"); 933 codes.put("FR", "France"); 934 codes.put("GF", "French Guiana"); 935 codes.put("PF", "French Polynesia"); 936 codes.put("TF", "French Southern Territories"); 937 codes.put("GA", "Gabon"); 938 codes.put("GM", "Gambia"); 939 codes.put("GE", "Georgia"); 940 codes.put("DE", "Germany"); 941 codes.put("GH", "Ghana"); 942 codes.put("GI", "Gibraltar"); 943 codes.put("GR", "Greece"); 944 codes.put("GL", "Greenland"); 945 codes.put("GD", "Grenada"); 946 codes.put("GP", "Guadeloupe"); 947 codes.put("GU", "Guam"); 948 codes.put("GT", "Guatemala"); 949 codes.put("GG", "Guernsey"); 950 codes.put("GN", "Guinea"); 951 codes.put("GW", "Guinea-Bissau"); 952 codes.put("GY", "Guyana"); 953 codes.put("HT", "Haiti"); 954 codes.put("HM", "Heard & McDonald Islands"); 955 codes.put("HN", "Honduras"); 956 codes.put("HK", "Hong Kong SAR China"); 957 codes.put("HU", "Hungary"); 958 codes.put("IS", "Iceland"); 959 codes.put("IN", "India"); 960 codes.put("ID", "Indonesia"); 961 codes.put("IR", "Iran"); 962 codes.put("IQ", "Iraq"); 963 codes.put("IE", "Ireland"); 964 codes.put("IM", "Isle of Man"); 965 codes.put("IL", "Israel"); 966 codes.put("IT", "Italy"); 967 codes.put("JM", "Jamaica"); 968 codes.put("JP", "Japan"); 969 codes.put("JE", "Jersey"); 970 codes.put("JO", "Jordan"); 971 codes.put("KZ", "Kazakhstan"); 972 codes.put("KE", "Kenya"); 973 codes.put("KI", "Kiribati"); 974 codes.put("KW", "Kuwait"); 975 codes.put("KG", "Kyrgyzstan"); 976 codes.put("LA", "Laos"); 977 codes.put("LV", "Latvia"); 978 codes.put("LB", "Lebanon"); 979 codes.put("LS", "Lesotho"); 980 codes.put("LR", "Liberia"); 981 codes.put("LY", "Libya"); 982 codes.put("LI", "Liechtenstein"); 983 codes.put("LT", "Lithuania"); 984 codes.put("LU", "Luxembourg"); 985 codes.put("MO", "Macao SAR China"); 986 codes.put("MG", "Madagascar"); 987 codes.put("MW", "Malawi"); 988 codes.put("MY", "Malaysia"); 989 codes.put("MV", "Maldives"); 990 codes.put("ML", "Mali"); 991 codes.put("MT", "Malta"); 992 codes.put("MH", "Marshall Islands"); 993 codes.put("MQ", "Martinique"); 994 codes.put("MR", "Mauritania"); 995 codes.put("MU", "Mauritius"); 996 codes.put("YT", "Mayotte"); 997 codes.put("MX", "Mexico"); 998 codes.put("FM", "Micronesia"); 999 codes.put("MD", "Moldova"); 1000 codes.put("MC", "Monaco"); 1001 codes.put("MN", "Mongolia"); 1002 codes.put("ME", "Montenegro"); 1003 codes.put("MS", "Montserrat"); 1004 codes.put("MA", "Morocco"); 1005 codes.put("MZ", "Mozambique"); 1006 codes.put("MM", "Myanmar (Burma)"); 1007 codes.put("NA", "Namibia"); 1008 codes.put("NR", "Nauru"); 1009 codes.put("NP", "Nepal"); 1010 codes.put("NL", "Netherlands"); 1011 codes.put("NC", "New Caledonia"); 1012 codes.put("NZ", "New Zealand"); 1013 codes.put("NI", "Nicaragua"); 1014 codes.put("NE", "Niger"); 1015 codes.put("NG", "Nigeria"); 1016 codes.put("NU", "Niue"); 1017 codes.put("NF", "Norfolk Island"); 1018 codes.put("KP", "North Korea"); 1019 codes.put("MK", "North Macedonia"); 1020 codes.put("MP", "Northern Mariana Islands"); 1021 codes.put("NO", "Norway"); 1022 codes.put("OM", "Oman"); 1023 codes.put("PK", "Pakistan"); 1024 codes.put("PW", "Palau"); 1025 codes.put("PS", "Palestinian Territories"); 1026 codes.put("PA", "Panama"); 1027 codes.put("PG", "Papua New Guinea"); 1028 codes.put("PY", "Paraguay"); 1029 codes.put("PE", "Peru"); 1030 codes.put("PH", "Philippines"); 1031 codes.put("PN", "Pitcairn Islands"); 1032 codes.put("PL", "Poland"); 1033 codes.put("PT", "Portugal"); 1034 codes.put("PR", "Puerto Rico"); 1035 codes.put("QA", "Qatar"); 1036 codes.put("RE", "Réunion"); 1037 codes.put("RO", "Romania"); 1038 codes.put("RU", "Russia"); 1039 codes.put("RW", "Rwanda"); 1040 codes.put("WS", "Samoa"); 1041 codes.put("SM", "San Marino"); 1042 codes.put("ST", "São Tomé & Príncipe"); 1043 codes.put("SA", "Saudi Arabia"); 1044 codes.put("SN", "Senegal"); 1045 codes.put("RS", "Serbia"); 1046 codes.put("SC", "Seychelles"); 1047 codes.put("SL", "Sierra Leone"); 1048 codes.put("SG", "Singapore"); 1049 codes.put("SX", "Sint Maarten"); 1050 codes.put("SK", "Slovakia"); 1051 codes.put("SI", "Slovenia"); 1052 codes.put("SB", "Solomon Islands"); 1053 codes.put("SO", "Somalia"); 1054 codes.put("ZA", "South Africa"); 1055 codes.put("GS", "South Georgia & South Sandwich Islands"); 1056 codes.put("KR", "South Korea"); 1057 codes.put("SS", "South Sudan"); 1058 codes.put("ES", "Spain"); 1059 codes.put("LK", "Sri Lanka"); 1060 codes.put("BL", "St. Barthélemy"); 1061 codes.put("SH", "St. Helena"); 1062 codes.put("KN", "St. Kitts & Nevis"); 1063 codes.put("LC", "St. Lucia"); 1064 codes.put("MF", "St. Martin"); 1065 codes.put("PM", "St. Pierre & Miquelon"); 1066 codes.put("VC", "St. Vincent & Grenadines"); 1067 codes.put("SD", "Sudan"); 1068 codes.put("SR", "Suriname"); 1069 codes.put("SJ", "Svalbard & Jan Mayen"); 1070 codes.put("SE", "Sweden"); 1071 codes.put("CH", "Switzerland"); 1072 codes.put("SY", "Syria"); 1073 codes.put("TW", "Taiwan"); 1074 codes.put("TJ", "Tajikistan"); 1075 codes.put("TZ", "Tanzania"); 1076 codes.put("TH", "Thailand"); 1077 codes.put("TL", "Timor-Leste"); 1078 codes.put("TG", "Togo"); 1079 codes.put("TK", "Tokelau"); 1080 codes.put("TO", "Tonga"); 1081 codes.put("TT", "Trinidad & Tobago"); 1082 codes.put("TN", "Tunisia"); 1083 codes.put("TR", "Turkey"); 1084 codes.put("TM", "Turkmenistan"); 1085 codes.put("TC", "Turks & Caicos Islands"); 1086 codes.put("TV", "Tuvalu"); 1087 codes.put("UM", "U.S. Outlying Islands"); 1088 codes.put("VI", "U.S. Virgin Islands"); 1089 codes.put("UG", "Uganda"); 1090 codes.put("UA", "Ukraine"); 1091 codes.put("AE", "United Arab Emirates"); 1092 codes.put("GB", "United Kingdom"); 1093 codes.put("US", "United States"); 1094 codes.put("UY", "Uruguay"); 1095 codes.put("UZ", "Uzbekistan"); 1096 codes.put("VU", "Vanuatu"); 1097 codes.put("VA", "Vatican City"); 1098 codes.put("VE", "Venezuela"); 1099 codes.put("VN", "Vietnam"); 1100 codes.put("WF", "Wallis & Futuna"); 1101 codes.put("EH", "Western Sahara"); 1102 codes.put("YE", "Yemen"); 1103 codes.put("ZM", "Zambia"); 1104 codes.put("ZW", "Zimbabwe"); 1105 1106 // 3 letter codes 1107 codes.put("ABW", "Aruba"); 1108 codes.put("AFG", "Afghanistan"); 1109 codes.put("AGO", "Angola"); 1110 codes.put("AIA", "Anguilla"); 1111 codes.put("ALA", "Åland Islands"); 1112 codes.put("ALB", "Albania"); 1113 codes.put("AND", "Andorra"); 1114 codes.put("ARE", "United Arab Emirates"); 1115 codes.put("ARG", "Argentina"); 1116 codes.put("ARM", "Armenia"); 1117 codes.put("ASM", "American Samoa"); 1118 codes.put("ATA", "Antarctica"); 1119 codes.put("ATF", "French Southern Territories"); 1120 codes.put("ATG", "Antigua and Barbuda"); 1121 codes.put("AUS", "Australia"); 1122 codes.put("AUT", "Austria"); 1123 codes.put("AZE", "Azerbaijan"); 1124 codes.put("BDI", "Burundi"); 1125 codes.put("BEL", "Belgium"); 1126 codes.put("BEN", "Benin"); 1127 codes.put("BES", "Bonaire, Sint Eustatius and Saba"); 1128 codes.put("BFA", "Burkina Faso"); 1129 codes.put("BGD", "Bangladesh"); 1130 codes.put("BGR", "Bulgaria"); 1131 codes.put("BHR", "Bahrain"); 1132 codes.put("BHS", "Bahamas"); 1133 codes.put("BIH", "Bosnia and Herzegovina"); 1134 codes.put("BLM", "Saint Barthélemy"); 1135 codes.put("BLR", "Belarus"); 1136 codes.put("BLZ", "Belize"); 1137 codes.put("BMU", "Bermuda"); 1138 codes.put("BOL", "Bolivia, Plurinational State of"); 1139 codes.put("BRA", "Brazil"); 1140 codes.put("BRB", "Barbados"); 1141 codes.put("BRN", "Brunei Darussalam"); 1142 codes.put("BTN", "Bhutan"); 1143 codes.put("BVT", "Bouvet Island"); 1144 codes.put("BWA", "Botswana"); 1145 codes.put("CAF", "Central African Republic"); 1146 codes.put("CAN", "Canada"); 1147 codes.put("CCK", "Cocos (Keeling) Islands"); 1148 codes.put("CHE", "Switzerland"); 1149 codes.put("CHL", "Chile"); 1150 codes.put("CHN", "China"); 1151 codes.put("CIV", "Côte d'Ivoire"); 1152 codes.put("CMR", "Cameroon"); 1153 codes.put("COD", "Congo, the Democratic Republic of the"); 1154 codes.put("COG", "Congo"); 1155 codes.put("COK", "Cook Islands"); 1156 codes.put("COL", "Colombia"); 1157 codes.put("COM", "Comoros"); 1158 codes.put("CPV", "Cabo Verde"); 1159 codes.put("CRI", "Costa Rica"); 1160 codes.put("CUB", "Cuba"); 1161 codes.put("CUW", "Curaçao"); 1162 codes.put("CXR", "Christmas Island"); 1163 codes.put("CYM", "Cayman Islands"); 1164 codes.put("CYP", "Cyprus"); 1165 codes.put("CZE", "Czechia"); 1166 codes.put("DEU", "Germany"); 1167 codes.put("DJI", "Djibouti"); 1168 codes.put("DMA", "Dominica"); 1169 codes.put("DNK", "Denmark"); 1170 codes.put("DOM", "Dominican Republic"); 1171 codes.put("DZA", "Algeria"); 1172 codes.put("ECU", "Ecuador"); 1173 codes.put("EGY", "Egypt"); 1174 codes.put("ERI", "Eritrea"); 1175 codes.put("ESH", "Western Sahara"); 1176 codes.put("ESP", "Spain"); 1177 codes.put("EST", "Estonia"); 1178 codes.put("ETH", "Ethiopia"); 1179 codes.put("FIN", "Finland"); 1180 codes.put("FJI", "Fiji"); 1181 codes.put("FLK", "Falkland Islands (Malvinas)"); 1182 codes.put("FRA", "France"); 1183 codes.put("FRO", "Faroe Islands"); 1184 codes.put("FSM", "Micronesia, Federated States of"); 1185 codes.put("GAB", "Gabon"); 1186 codes.put("GBR", "United Kingdom"); 1187 codes.put("GEO", "Georgia"); 1188 codes.put("GGY", "Guernsey"); 1189 codes.put("GHA", "Ghana"); 1190 codes.put("GIB", "Gibraltar"); 1191 codes.put("GIN", "Guinea"); 1192 codes.put("GLP", "Guadeloupe"); 1193 codes.put("GMB", "Gambia"); 1194 codes.put("GNB", "Guinea-Bissau"); 1195 codes.put("GNQ", "Equatorial Guinea"); 1196 codes.put("GRC", "Greece"); 1197 codes.put("GRD", "Grenada"); 1198 codes.put("GRL", "Greenland"); 1199 codes.put("GTM", "Guatemala"); 1200 codes.put("GUF", "French Guiana"); 1201 codes.put("GUM", "Guam"); 1202 codes.put("GUY", "Guyana"); 1203 codes.put("HKG", "Hong Kong"); 1204 codes.put("HMD", "Heard Island and McDonald Islands"); 1205 codes.put("HND", "Honduras"); 1206 codes.put("HRV", "Croatia"); 1207 codes.put("HTI", "Haiti"); 1208 codes.put("HUN", "Hungary"); 1209 codes.put("IDN", "Indonesia"); 1210 codes.put("IMN", "Isle of Man"); 1211 codes.put("IND", "India"); 1212 codes.put("IOT", "British Indian Ocean Territory"); 1213 codes.put("IRL", "Ireland"); 1214 codes.put("IRN", "Iran, Islamic Republic of"); 1215 codes.put("IRQ", "Iraq"); 1216 codes.put("ISL", "Iceland"); 1217 codes.put("ISR", "Israel"); 1218 codes.put("ITA", "Italy"); 1219 codes.put("JAM", "Jamaica"); 1220 codes.put("JEY", "Jersey"); 1221 codes.put("JOR", "Jordan"); 1222 codes.put("JPN", "Japan"); 1223 codes.put("KAZ", "Kazakhstan"); 1224 codes.put("KEN", "Kenya"); 1225 codes.put("KGZ", "Kyrgyzstan"); 1226 codes.put("KHM", "Cambodia"); 1227 codes.put("KIR", "Kiribati"); 1228 codes.put("KNA", "Saint Kitts and Nevis"); 1229 codes.put("KOR", "Korea, Republic of"); 1230 codes.put("KWT", "Kuwait"); 1231 codes.put("LAO", "Lao People's Democratic Republic"); 1232 codes.put("LBN", "Lebanon"); 1233 codes.put("LBR", "Liberia"); 1234 codes.put("LBY", "Libya"); 1235 codes.put("LCA", "Saint Lucia"); 1236 codes.put("LIE", "Liechtenstein"); 1237 codes.put("LKA", "Sri Lanka"); 1238 codes.put("LSO", "Lesotho"); 1239 codes.put("LTU", "Lithuania"); 1240 codes.put("LUX", "Luxembourg"); 1241 codes.put("LVA", "Latvia"); 1242 codes.put("MAC", "Macao"); 1243 codes.put("MAF", "Saint Martin (French part)"); 1244 codes.put("MAR", "Morocco"); 1245 codes.put("MCO", "Monaco"); 1246 codes.put("MDA", "Moldova, Republic of"); 1247 codes.put("MDG", "Madagascar"); 1248 codes.put("MDV", "Maldives"); 1249 codes.put("MEX", "Mexico"); 1250 codes.put("MHL", "Marshall Islands"); 1251 codes.put("MKD", "Macedonia, the former Yugoslav Republic of"); 1252 codes.put("MLI", "Mali"); 1253 codes.put("MLT", "Malta"); 1254 codes.put("MMR", "Myanmar"); 1255 codes.put("MNE", "Montenegro"); 1256 codes.put("MNG", "Mongolia"); 1257 codes.put("MNP", "Northern Mariana Islands"); 1258 codes.put("MOZ", "Mozambique"); 1259 codes.put("MRT", "Mauritania"); 1260 codes.put("MSR", "Montserrat"); 1261 codes.put("MTQ", "Martinique"); 1262 codes.put("MUS", "Mauritius"); 1263 codes.put("MWI", "Malawi"); 1264 codes.put("MYS", "Malaysia"); 1265 codes.put("MYT", "Mayotte"); 1266 codes.put("NAM", "Namibia"); 1267 codes.put("NCL", "New Caledonia"); 1268 codes.put("NER", "Niger"); 1269 codes.put("NFK", "Norfolk Island"); 1270 codes.put("NGA", "Nigeria"); 1271 codes.put("NIC", "Nicaragua"); 1272 codes.put("NIU", "Niue"); 1273 codes.put("NLD", "Netherlands"); 1274 codes.put("NOR", "Norway"); 1275 codes.put("NPL", "Nepal"); 1276 codes.put("NRU", "Nauru"); 1277 codes.put("NZL", "New Zealand"); 1278 codes.put("OMN", "Oman"); 1279 codes.put("PAK", "Pakistan"); 1280 codes.put("PAN", "Panama"); 1281 codes.put("PCN", "Pitcairn"); 1282 codes.put("PER", "Peru"); 1283 codes.put("PHL", "Philippines"); 1284 codes.put("PLW", "Palau"); 1285 codes.put("PNG", "Papua New Guinea"); 1286 codes.put("POL", "Poland"); 1287 codes.put("PRI", "Puerto Rico"); 1288 codes.put("PRK", "Korea, Democratic People's Republic of"); 1289 codes.put("PRT", "Portugal"); 1290 codes.put("PRY", "Paraguay"); 1291 codes.put("PSE", "Palestine, State of"); 1292 codes.put("PYF", "French Polynesia"); 1293 codes.put("QAT", "Qatar"); 1294 codes.put("REU", "Réunion"); 1295 codes.put("ROU", "Romania"); 1296 codes.put("RUS", "Russian Federation"); 1297 codes.put("RWA", "Rwanda"); 1298 codes.put("SAU", "Saudi Arabia"); 1299 codes.put("SDN", "Sudan"); 1300 codes.put("SEN", "Senegal"); 1301 codes.put("SGP", "Singapore"); 1302 codes.put("SGS", "South Georgia and the South Sandwich Islands"); 1303 codes.put("SHN", "Saint Helena, Ascension and Tristan da Cunha"); 1304 codes.put("SJM", "Svalbard and Jan Mayen"); 1305 codes.put("SLB", "Solomon Islands"); 1306 codes.put("SLE", "Sierra Leone"); 1307 codes.put("SLV", "El Salvador"); 1308 codes.put("SMR", "San Marino"); 1309 codes.put("SOM", "Somalia"); 1310 codes.put("SPM", "Saint Pierre and Miquelon"); 1311 codes.put("SRB", "Serbia"); 1312 codes.put("SSD", "South Sudan"); 1313 codes.put("STP", "Sao Tome and Principe"); 1314 codes.put("SUR", "Suriname"); 1315 codes.put("SVK", "Slovakia"); 1316 codes.put("SVN", "Slovenia"); 1317 codes.put("SWE", "Sweden"); 1318 codes.put("SWZ", "Swaziland"); 1319 codes.put("SXM", "Sint Maarten (Dutch part)"); 1320 codes.put("SYC", "Seychelles"); 1321 codes.put("SYR", "Syrian Arab Republic"); 1322 codes.put("TCA", "Turks and Caicos Islands"); 1323 codes.put("TCD", "Chad"); 1324 codes.put("TGO", "Togo"); 1325 codes.put("THA", "Thailand"); 1326 codes.put("TJK", "Tajikistan"); 1327 codes.put("TKL", "Tokelau"); 1328 codes.put("TKM", "Turkmenistan"); 1329 codes.put("TLS", "Timor-Leste"); 1330 codes.put("TON", "Tonga"); 1331 codes.put("TTO", "Trinidad and Tobago"); 1332 codes.put("TUN", "Tunisia"); 1333 codes.put("TUR", "Turkey"); 1334 codes.put("TUV", "Tuvalu"); 1335 codes.put("TWN", "Taiwan, Province of China"); 1336 codes.put("TZA", "Tanzania, United Republic of"); 1337 codes.put("UGA", "Uganda"); 1338 codes.put("UKR", "Ukraine"); 1339 codes.put("UMI", "United States Minor Outlying Islands"); 1340 codes.put("URY", "Uruguay"); 1341 codes.put("USA", "United States of America"); 1342 codes.put("UZB", "Uzbekistan"); 1343 codes.put("VAT", "Holy See"); 1344 codes.put("VCT", "Saint Vincent and the Grenadines"); 1345 codes.put("VEN", "Venezuela, Bolivarian Republic of"); 1346 codes.put("VGB", "Virgin Islands, British"); 1347 codes.put("VIR", "Virgin Islands, U.S."); 1348 codes.put("VNM", "Viet Nam"); 1349 codes.put("VUT", "Vanuatu"); 1350 codes.put("WLF", "Wallis and Futuna"); 1351 codes.put("WSM", "Samoa"); 1352 codes.put("YEM", "Yemen"); 1353 codes.put("ZAF", "South Africa"); 1354 codes.put("ZMB", "Zambia"); 1355 codes.put("ZWE", "Zimbabwe"); 1356 return codes; 1357 } 1358 1359 protected String getErrorMessage(String errorCode, String theFirstParam, String theSecondParam) { 1360 return myFhirContext.getLocalizer().getMessage(getClass(), errorCode, theFirstParam, theSecondParam); 1361 } 1362}