001package ca.uhn.fhir.context.support; 002 003/* 004 * #%L 005 * HAPI FHIR - Core Library 006 * %% 007 * Copyright (C) 2014 - 2021 Smile CDR, Inc. 008 * %% 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 * #L% 021 */ 022 023import ca.uhn.fhir.context.FhirContext; 024import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; 025import ca.uhn.fhir.util.ParametersUtil; 026import org.apache.commons.lang3.Validate; 027import org.apache.commons.lang3.builder.EqualsBuilder; 028import org.apache.commons.lang3.builder.HashCodeBuilder; 029import org.hl7.fhir.instance.model.api.IBase; 030import org.hl7.fhir.instance.model.api.IBaseParameters; 031import org.hl7.fhir.instance.model.api.IBaseResource; 032import org.hl7.fhir.instance.model.api.IPrimitiveType; 033 034import javax.annotation.Nonnull; 035import javax.annotation.Nullable; 036import java.util.ArrayList; 037import java.util.Arrays; 038import java.util.Collections; 039import java.util.Iterator; 040import java.util.List; 041import java.util.Set; 042import java.util.function.Supplier; 043import java.util.stream.Collectors; 044 045import static org.apache.commons.lang3.StringUtils.defaultString; 046import static org.apache.commons.lang3.StringUtils.isNotBlank; 047 048/** 049 * This interface is a version-independent representation of the 050 * various functions that can be provided by validation and terminology 051 * services. 052 * <p> 053 * This interface is invoked directly by internal parts of the HAPI FHIR API, including the 054 * Validator and the FHIRPath evaluator. It is used to supply artifacts required for validation 055 * (e.g. StructureDefinition resources, ValueSet resources, etc.) and also to provide 056 * terminology functions such as code validation, ValueSet expansion, etc. 057 * </p> 058 * <p> 059 * Implementations are not required to implement all of the functions 060 * in this interface; in fact it is expected that most won't. Any 061 * methods which are not implemented may simply return <code>null</code> 062 * and calling code is expected to be able to handle this. Generally, a 063 * series of implementations of this interface will be joined together using 064 * the 065 * <a href="https://hapifhir.io/hapi-fhir/apidocs/hapi-fhir-validation/org/hl7/fhir/common/hapi/validation/ValidationSupportChain2.html">ValidationSupportChain</a> 066 * class. 067 * </p> 068 * <p> 069 * See <a href="https://hapifhir.io/hapi-fhir/docs/validation/validation_support_modules.html">Validation Support Modules</a> 070 * for information on how to assemble and configure implementations of this interface. See also 071 * the <code>org.hl7.fhir.common.hapi.validation.support</code> 072 * <a href="https://hapifhir.io/hapi-fhir/apidocs/hapi-fhir-validation/org/hl7/fhir/common/hapi/validation/package-summary.html">package summary</a> 073 * in the <code>hapi-fhir-validation</code> module for many implementations of this interface. 074 * </p> 075 * 076 * @since 5.0.0 077 */ 078public interface IValidationSupport { 079 String URL_PREFIX_VALUE_SET = "http://hl7.org/fhir/ValueSet/"; 080 081 082 /** 083 * Expands the given portion of a ValueSet 084 * 085 * @param theValidationSupportContext The validation support module will be passed in to this method. This is convenient in cases where the operation needs to make calls to 086 * other method in the support chain, so that they can be passed through the entire chain. Implementations of this interface may always safely ignore this parameter. 087 * @param theExpansionOptions If provided (may be <code>null</code>), contains options controlling the expansion 088 * @param theValueSetToExpand The valueset that should be expanded 089 * @return The expansion, or null 090 */ 091 @Nullable 092 default ValueSetExpansionOutcome expandValueSet(ValidationSupportContext theValidationSupportContext, @Nullable ValueSetExpansionOptions theExpansionOptions, @Nonnull IBaseResource theValueSetToExpand) { 093 return null; 094 } 095 096 /** 097 * Load and return all conformance resources associated with this 098 * validation support module. This method may return null if it doesn't 099 * make sense for a given module. 100 */ 101 @Nullable 102 default List<IBaseResource> fetchAllConformanceResources() { 103 return null; 104 } 105 106 /** 107 * Load and return all possible structure definitions 108 */ 109 @Nullable 110 default <T extends IBaseResource> List<T> fetchAllStructureDefinitions() { 111 return null; 112 } 113 114 /** 115 * Load and return all possible structure definitions aside from resource definitions themselves 116 */ 117 @Nullable 118 default <T extends IBaseResource> List<T> fetchAllNonBaseStructureDefinitions() { 119 List<T> retVal = fetchAllStructureDefinitions(); 120 if (retVal != null) { 121 List<T> newList = new ArrayList<>(retVal.size()); 122 for (T next : retVal) { 123 String url = defaultString(getFhirContext().newTerser().getSinglePrimitiveValueOrNull(next, "url")); 124 if (url.startsWith("http://hl7.org/fhir/StructureDefinition/")) { 125 String lastPart = url.substring("http://hl7.org/fhir/StructureDefinition/".length()); 126 if (getFhirContext().getResourceTypes().contains(lastPart)) { 127 continue; 128 } 129 } 130 131 newList.add(next); 132 } 133 134 retVal = newList; 135 } 136 137 return retVal; 138 } 139 140 /** 141 * Fetch a code system by ID 142 * 143 * @param theSystem The code system 144 * @return The valueset (must not be null, but can be an empty ValueSet) 145 */ 146 @Nullable 147 default IBaseResource fetchCodeSystem(String theSystem) { 148 return null; 149 } 150 151 /** 152 * Loads a resource needed by the validation (a StructureDefinition, or a 153 * ValueSet) 154 * 155 * <p> 156 * Note: Since 5.3.0, {@literal theClass} can be {@literal null} 157 * </p> 158 * 159 * @param theClass The type of the resource to load, or <code>null</code> to return any resource with the given canonical URI 160 * @param theUri The resource URI 161 * @return Returns the resource, or <code>null</code> if no resource with the 162 * given URI can be found 163 */ 164 @SuppressWarnings("unchecked") 165 @Nullable 166 default <T extends IBaseResource> T fetchResource(@Nullable Class<T> theClass, String theUri) { 167 Validate.notBlank(theUri, "theUri must not be null or blank"); 168 169 if (theClass == null) { 170 Supplier<IBaseResource>[] sources = new Supplier[]{ 171 () -> fetchStructureDefinition(theUri), 172 () -> fetchValueSet(theUri), 173 () -> fetchCodeSystem(theUri) 174 }; 175 return (T) Arrays 176 .stream(sources) 177 .map(t -> t.get()) 178 .filter(t -> t != null) 179 .findFirst() 180 .orElse(null); 181 } 182 183 switch (getFhirContext().getResourceType(theClass)) { 184 case "StructureDefinition": 185 return theClass.cast(fetchStructureDefinition(theUri)); 186 case "ValueSet": 187 return theClass.cast(fetchValueSet(theUri)); 188 case "CodeSystem": 189 return theClass.cast(fetchCodeSystem(theUri)); 190 } 191 192 if (theUri.startsWith(URL_PREFIX_VALUE_SET)) { 193 return theClass.cast(fetchValueSet(theUri)); 194 } 195 196 return null; 197 } 198 199 @Nullable 200 default IBaseResource fetchStructureDefinition(String theUrl) { 201 return null; 202 } 203 204 /** 205 * Returns <code>true</code> if codes in the given code system can be expanded 206 * or validated 207 * 208 * @param theValidationSupportContext The validation support module will be passed in to this method. This is convenient in cases where the operation needs to make calls to 209 * other method in the support chain, so that they can be passed through the entire chain. Implementations of this interface may always safely ignore this parameter. 210 * @param theSystem The URI for the code system, e.g. <code>"http://loinc.org"</code> 211 * @return Returns <code>true</code> if codes in the given code system can be 212 * validated 213 */ 214 default boolean isCodeSystemSupported(ValidationSupportContext theValidationSupportContext, String theSystem) { 215 return false; 216 } 217 218 /** 219 * Fetch the given ValueSet by URL 220 */ 221 @Nullable 222 default IBaseResource fetchValueSet(String theValueSetUrl) { 223 return null; 224 } 225 226 /** 227 * Validates that the given code exists and if possible returns a display 228 * name. This method is called to check codes which are found in "example" 229 * binding fields (e.g. <code>Observation.code</code> in the default profile. 230 * 231 * @param theValidationSupportContext The validation support module will be passed in to this method. This is convenient in cases where the operation needs to make calls to 232 * other method in the support chain, so that they can be passed through the entire chain. Implementations of this interface may always safely ignore this parameter. 233 * @param theOptions Provides options controlling the validation 234 * @param theCodeSystem The code system, e.g. "<code>http://loinc.org</code>" 235 * @param theCode The code, e.g. "<code>1234-5</code>" 236 * @param theDisplay The display name, if it should also be validated 237 * @return Returns a validation result object 238 */ 239 @Nullable 240 default CodeValidationResult validateCode(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, String theValueSetUrl) { 241 return null; 242 } 243 244 /** 245 * Validates that the given code exists and if possible returns a display 246 * name. This method is called to check codes which are found in "example" 247 * binding fields (e.g. <code>Observation.code</code> in the default profile. 248 * 249 * @param theValidationSupportContext The validation support module will be passed in to this method. This is convenient in cases where the operation needs to make calls to 250 * other method in the support chain, so that they can be passed through the entire chain. Implementations of this interface may always safely ignore this parameter. 251 * @param theCodeSystem The code system, e.g. "<code>http://loinc.org</code>" 252 * @param theCode The code, e.g. "<code>1234-5</code>" 253 * @param theDisplay The display name, if it should also be validated 254 * @param theValueSet The ValueSet to validate against. Must not be null, and must be a ValueSet resource. 255 * @return Returns a validation result object, or <code>null</code> if this validation support module can not handle this kind of request 256 */ 257 @Nullable 258 default CodeValidationResult validateCodeInValueSet(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, @Nonnull IBaseResource theValueSet) { 259 return null; 260 } 261 262 /** 263 * Look up a code using the system and code value 264 * 265 * @param theValidationSupportContext The validation support module will be passed in to this method. This is convenient in cases where the operation needs to make calls to 266 * other method in the support chain, so that they can be passed through the entire chain. Implementations of this interface may always safely ignore this parameter. 267 * @param theSystem The CodeSystem URL 268 * @param theCode The code 269 */ 270 @Nullable 271 default LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode) { 272 return null; 273 } 274 275 /** 276 * Returns <code>true</code> if the given valueset can be validated by the given 277 * validation support module 278 * 279 * @param theValidationSupportContext The validation support module will be passed in to this method. This is convenient in cases where the operation needs to make calls to 280 * other method in the support chain, so that they can be passed through the entire chain. Implementations of this interface may always safely ignore this parameter. 281 * @param theValueSetUrl The ValueSet canonical URL 282 */ 283 default boolean isValueSetSupported(ValidationSupportContext theValidationSupportContext, String theValueSetUrl) { 284 return false; 285 } 286 287 /** 288 * Generate a snapshot from the given differential profile. 289 * 290 * @param theValidationSupportContext The validation support module will be passed in to this method. This is convenient in cases where the operation needs to make calls to 291 * other method in the support chain, so that they can be passed through the entire chain. Implementations of this interface may always safely ignore this parameter. 292 * @return Returns null if this module does not know how to handle this request 293 */ 294 @Nullable 295 default IBaseResource generateSnapshot(ValidationSupportContext theValidationSupportContext, IBaseResource theInput, String theUrl, String theWebUrl, String theProfileName) { 296 return null; 297 } 298 299 /** 300 * Returns the FHIR Context associated with this module 301 */ 302 FhirContext getFhirContext(); 303 304 /** 305 * This method clears any temporary caches within the validation support. It is mainly intended for unit tests, 306 * but could be used in non-test scenarios as well. 307 */ 308 default void invalidateCaches() { 309 // nothing 310 } 311 312 /** 313 * Attempt to translate the given concept from one code system to another 314 */ 315 @Nullable 316 default TranslateConceptResults translateConcept(TranslateCodeRequest theRequest) { 317 return null; 318 } 319 320 321 enum IssueSeverity { 322 /** 323 * The issue caused the action to fail, and no further checking could be performed. 324 */ 325 FATAL, 326 /** 327 * The issue is sufficiently important to cause the action to fail. 328 */ 329 ERROR, 330 /** 331 * The issue is not important enough to cause the action to fail, but may cause it to be performed suboptimally or in a way that is not as desired. 332 */ 333 WARNING, 334 /** 335 * The issue has no relation to the degree of success of the action. 336 */ 337 INFORMATION 338 } 339 340 class ConceptDesignation { 341 342 private String myLanguage; 343 private String myUseSystem; 344 private String myUseCode; 345 private String myUseDisplay; 346 private String myValue; 347 348 public String getLanguage() { 349 return myLanguage; 350 } 351 352 public ConceptDesignation setLanguage(String theLanguage) { 353 myLanguage = theLanguage; 354 return this; 355 } 356 357 public String getUseSystem() { 358 return myUseSystem; 359 } 360 361 public ConceptDesignation setUseSystem(String theUseSystem) { 362 myUseSystem = theUseSystem; 363 return this; 364 } 365 366 public String getUseCode() { 367 return myUseCode; 368 } 369 370 public ConceptDesignation setUseCode(String theUseCode) { 371 myUseCode = theUseCode; 372 return this; 373 } 374 375 public String getUseDisplay() { 376 return myUseDisplay; 377 } 378 379 public ConceptDesignation setUseDisplay(String theUseDisplay) { 380 myUseDisplay = theUseDisplay; 381 return this; 382 } 383 384 public String getValue() { 385 return myValue; 386 } 387 388 public ConceptDesignation setValue(String theValue) { 389 myValue = theValue; 390 return this; 391 } 392 } 393 394 abstract class BaseConceptProperty { 395 private final String myPropertyName; 396 397 /** 398 * Constructor 399 */ 400 protected BaseConceptProperty(String thePropertyName) { 401 myPropertyName = thePropertyName; 402 } 403 404 public String getPropertyName() { 405 return myPropertyName; 406 } 407 } 408 409 class StringConceptProperty extends BaseConceptProperty { 410 private final String myValue; 411 412 /** 413 * Constructor 414 * 415 * @param theName The name 416 */ 417 public StringConceptProperty(String theName, String theValue) { 418 super(theName); 419 myValue = theValue; 420 } 421 422 public String getValue() { 423 return myValue; 424 } 425 } 426 427 class CodingConceptProperty extends BaseConceptProperty { 428 private final String myCode; 429 private final String myCodeSystem; 430 private final String myDisplay; 431 432 /** 433 * Constructor 434 * 435 * @param theName The name 436 */ 437 public CodingConceptProperty(String theName, String theCodeSystem, String theCode, String theDisplay) { 438 super(theName); 439 myCodeSystem = theCodeSystem; 440 myCode = theCode; 441 myDisplay = theDisplay; 442 } 443 444 public String getCode() { 445 return myCode; 446 } 447 448 public String getCodeSystem() { 449 return myCodeSystem; 450 } 451 452 public String getDisplay() { 453 return myDisplay; 454 } 455 } 456 457 class CodeValidationResult { 458 private String myCode; 459 private String myMessage; 460 private IssueSeverity mySeverity; 461 private String myCodeSystemName; 462 private String myCodeSystemVersion; 463 private List<BaseConceptProperty> myProperties; 464 private String myDisplay; 465 466 public CodeValidationResult() { 467 super(); 468 } 469 470 public String getDisplay() { 471 return myDisplay; 472 } 473 474 public CodeValidationResult setDisplay(String theDisplay) { 475 myDisplay = theDisplay; 476 return this; 477 } 478 479 public String getCode() { 480 return myCode; 481 } 482 483 public CodeValidationResult setCode(String theCode) { 484 myCode = theCode; 485 return this; 486 } 487 488 String getCodeSystemName() { 489 return myCodeSystemName; 490 } 491 492 public CodeValidationResult setCodeSystemName(String theCodeSystemName) { 493 myCodeSystemName = theCodeSystemName; 494 return this; 495 } 496 497 public String getCodeSystemVersion() { 498 return myCodeSystemVersion; 499 } 500 501 public CodeValidationResult setCodeSystemVersion(String theCodeSystemVersion) { 502 myCodeSystemVersion = theCodeSystemVersion; 503 return this; 504 } 505 506 public String getMessage() { 507 return myMessage; 508 } 509 510 public CodeValidationResult setMessage(String theMessage) { 511 myMessage = theMessage; 512 return this; 513 } 514 515 public List<BaseConceptProperty> getProperties() { 516 return myProperties; 517 } 518 519 public void setProperties(List<BaseConceptProperty> theProperties) { 520 myProperties = theProperties; 521 } 522 523 public IssueSeverity getSeverity() { 524 return mySeverity; 525 } 526 527 public CodeValidationResult setSeverity(IssueSeverity theSeverity) { 528 mySeverity = theSeverity; 529 return this; 530 } 531 532 public boolean isOk() { 533 return isNotBlank(myCode); 534 } 535 536 public LookupCodeResult asLookupCodeResult(String theSearchedForSystem, String theSearchedForCode) { 537 LookupCodeResult retVal = new LookupCodeResult(); 538 retVal.setSearchedForSystem(theSearchedForSystem); 539 retVal.setSearchedForCode(theSearchedForCode); 540 if (isOk()) { 541 retVal.setFound(true); 542 retVal.setCodeDisplay(myDisplay); 543 retVal.setCodeSystemDisplayName(getCodeSystemName()); 544 retVal.setCodeSystemVersion(getCodeSystemVersion()); 545 } 546 return retVal; 547 } 548 549 /** 550 * Convenience method that returns {@link #getSeverity()} as an IssueSeverity code string 551 */ 552 public String getSeverityCode() { 553 String retVal = null; 554 if (getSeverity() != null) { 555 retVal = getSeverity().name().toLowerCase(); 556 } 557 return retVal; 558 } 559 560 /** 561 * Sets an issue severity as a string code. Value must be the name of 562 * one of the enum values in {@link IssueSeverity}. Value is case-insensitive. 563 */ 564 public CodeValidationResult setSeverityCode(@Nonnull String theIssueSeverity) { 565 setSeverity(IssueSeverity.valueOf(theIssueSeverity.toUpperCase())); 566 return this; 567 } 568 } 569 570 class ValueSetExpansionOutcome { 571 572 private final IBaseResource myValueSet; 573 private final String myError; 574 575 public ValueSetExpansionOutcome(IBaseResource theValueSet, String theError) { 576 myValueSet = theValueSet; 577 myError = theError; 578 } 579 580 public ValueSetExpansionOutcome(IBaseResource theValueSet) { 581 myValueSet = theValueSet; 582 myError = null; 583 } 584 585 public String getError() { 586 return myError; 587 } 588 589 public IBaseResource getValueSet() { 590 return myValueSet; 591 } 592 } 593 594 class LookupCodeResult { 595 596 private String myCodeDisplay; 597 private boolean myCodeIsAbstract; 598 private String myCodeSystemDisplayName; 599 private String myCodeSystemVersion; 600 private boolean myFound; 601 private String mySearchedForCode; 602 private String mySearchedForSystem; 603 private List<IValidationSupport.BaseConceptProperty> myProperties; 604 private List<ConceptDesignation> myDesignations; 605 606 /** 607 * Constructor 608 */ 609 public LookupCodeResult() { 610 super(); 611 } 612 613 public List<BaseConceptProperty> getProperties() { 614 if (myProperties == null) { 615 myProperties = new ArrayList<>(); 616 } 617 return myProperties; 618 } 619 620 public void setProperties(List<IValidationSupport.BaseConceptProperty> theProperties) { 621 myProperties = theProperties; 622 } 623 624 @Nonnull 625 public List<ConceptDesignation> getDesignations() { 626 if (myDesignations == null) { 627 myDesignations = new ArrayList<>(); 628 } 629 return myDesignations; 630 } 631 632 public String getCodeDisplay() { 633 return myCodeDisplay; 634 } 635 636 public void setCodeDisplay(String theCodeDisplay) { 637 myCodeDisplay = theCodeDisplay; 638 } 639 640 public String getCodeSystemDisplayName() { 641 return myCodeSystemDisplayName; 642 } 643 644 public void setCodeSystemDisplayName(String theCodeSystemDisplayName) { 645 myCodeSystemDisplayName = theCodeSystemDisplayName; 646 } 647 648 public String getCodeSystemVersion() { 649 return myCodeSystemVersion; 650 } 651 652 public void setCodeSystemVersion(String theCodeSystemVersion) { 653 myCodeSystemVersion = theCodeSystemVersion; 654 } 655 656 public String getSearchedForCode() { 657 return mySearchedForCode; 658 } 659 660 public LookupCodeResult setSearchedForCode(String theSearchedForCode) { 661 mySearchedForCode = theSearchedForCode; 662 return this; 663 } 664 665 public String getSearchedForSystem() { 666 return mySearchedForSystem; 667 } 668 669 public LookupCodeResult setSearchedForSystem(String theSearchedForSystem) { 670 mySearchedForSystem = theSearchedForSystem; 671 return this; 672 } 673 674 public boolean isCodeIsAbstract() { 675 return myCodeIsAbstract; 676 } 677 678 public void setCodeIsAbstract(boolean theCodeIsAbstract) { 679 myCodeIsAbstract = theCodeIsAbstract; 680 } 681 682 public boolean isFound() { 683 return myFound; 684 } 685 686 public LookupCodeResult setFound(boolean theFound) { 687 myFound = theFound; 688 return this; 689 } 690 691 public void throwNotFoundIfAppropriate() { 692 if (isFound() == false) { 693 throw new ResourceNotFoundException("Unable to find code[" + getSearchedForCode() + "] in system[" + getSearchedForSystem() + "]"); 694 } 695 } 696 697 public IBaseParameters toParameters(FhirContext theContext, List<? extends IPrimitiveType<String>> theProperties) { 698 699 IBaseParameters retVal = ParametersUtil.newInstance(theContext); 700 if (isNotBlank(getCodeSystemDisplayName())) { 701 ParametersUtil.addParameterToParametersString(theContext, retVal, "name", getCodeSystemDisplayName()); 702 } 703 if (isNotBlank(getCodeSystemVersion())) { 704 ParametersUtil.addParameterToParametersString(theContext, retVal, "version", getCodeSystemVersion()); 705 } 706 ParametersUtil.addParameterToParametersString(theContext, retVal, "display", getCodeDisplay()); 707 ParametersUtil.addParameterToParametersBoolean(theContext, retVal, "abstract", isCodeIsAbstract()); 708 709 if (myProperties != null) { 710 711 Set<String> properties = Collections.emptySet(); 712 if (theProperties != null) { 713 properties = theProperties 714 .stream() 715 .map(IPrimitiveType::getValueAsString) 716 .collect(Collectors.toSet()); 717 } 718 719 for (IValidationSupport.BaseConceptProperty next : myProperties) { 720 721 if (!properties.isEmpty()) { 722 if (!properties.contains(next.getPropertyName())) { 723 continue; 724 } 725 } 726 727 IBase property = ParametersUtil.addParameterToParameters(theContext, retVal, "property"); 728 ParametersUtil.addPartCode(theContext, property, "code", next.getPropertyName()); 729 730 if (next instanceof IValidationSupport.StringConceptProperty) { 731 IValidationSupport.StringConceptProperty prop = (IValidationSupport.StringConceptProperty) next; 732 ParametersUtil.addPartString(theContext, property, "value", prop.getValue()); 733 } else if (next instanceof IValidationSupport.CodingConceptProperty) { 734 IValidationSupport.CodingConceptProperty prop = (IValidationSupport.CodingConceptProperty) next; 735 ParametersUtil.addPartCoding(theContext, property, "value", prop.getCodeSystem(), prop.getCode(), prop.getDisplay()); 736 } else { 737 throw new IllegalStateException("Don't know how to handle " + next.getClass()); 738 } 739 } 740 } 741 742 if (myDesignations != null) { 743 for (ConceptDesignation next : myDesignations) { 744 745 IBase property = ParametersUtil.addParameterToParameters(theContext, retVal, "designation"); 746 ParametersUtil.addPartCode(theContext, property, "language", next.getLanguage()); 747 ParametersUtil.addPartCoding(theContext, property, "use", next.getUseSystem(), next.getUseCode(), next.getUseDisplay()); 748 ParametersUtil.addPartString(theContext, property, "value", next.getValue()); 749 } 750 } 751 752 return retVal; 753 } 754 755 public static LookupCodeResult notFound(String theSearchedForSystem, String theSearchedForCode) { 756 return new LookupCodeResult() 757 .setFound(false) 758 .setSearchedForSystem(theSearchedForSystem) 759 .setSearchedForCode(theSearchedForCode); 760 } 761 } 762 763 764 class TranslateCodeRequest { 765 private final String mySourceSystemUrl; 766 private final String mySourceCode; 767 private final String myTargetSystemUrl; 768 private final int myHashCode; 769 770 public TranslateCodeRequest(String theSourceSystemUrl, String theSourceCode, String theTargetSystemUrl) { 771 mySourceSystemUrl = theSourceSystemUrl; 772 mySourceCode = theSourceCode; 773 myTargetSystemUrl = theTargetSystemUrl; 774 775 myHashCode = new HashCodeBuilder(17, 37) 776 .append(mySourceSystemUrl) 777 .append(mySourceCode) 778 .append(myTargetSystemUrl) 779 .toHashCode(); 780 } 781 782 @Override 783 public boolean equals(Object theO) { 784 if (this == theO) { 785 return true; 786 } 787 788 if (theO == null || getClass() != theO.getClass()) { 789 return false; 790 } 791 792 TranslateCodeRequest that = (TranslateCodeRequest) theO; 793 794 return new EqualsBuilder() 795 .append(mySourceSystemUrl, that.mySourceSystemUrl) 796 .append(mySourceCode, that.mySourceCode) 797 .append(myTargetSystemUrl, that.myTargetSystemUrl) 798 .isEquals(); 799 } 800 801 @Override 802 public int hashCode() { 803 return myHashCode; 804 } 805 806 public String getSourceSystemUrl() { 807 return mySourceSystemUrl; 808 } 809 810 public String getSourceCode() { 811 return mySourceCode; 812 } 813 814 public String getTargetSystemUrl() { 815 return myTargetSystemUrl; 816 } 817 } 818 819 820 821}