001package org.hl7.fhir.dstu3.model; 002 003/*- 004 * #%L 005 * org.hl7.fhir.dstu3 006 * %% 007 * Copyright (C) 2014 - 2019 Health Level 7 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 023/* 024 Copyright (c) 2011+, HL7, Inc. 025 All rights reserved. 026 027 Redistribution and use in source and binary forms, with or without modification, 028 are permitted provided that the following conditions are met: 029 030 * Redistributions of source code must retain the above copyright notice, this 031 list of conditions and the following disclaimer. 032 * Redistributions in binary form must reproduce the above copyright notice, 033 this list of conditions and the following disclaimer in the documentation 034 and/or other materials provided with the distribution. 035 * Neither the name of HL7 nor the names of its contributors may be used to 036 endorse or promote products derived from this software without specific 037 prior written permission. 038 039 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 040 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 041 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 042 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 043 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 044 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 045 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 046 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 047 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 048 POSSIBILITY OF SUCH DAMAGE. 049 050*/ 051import static org.apache.commons.lang3.StringUtils.*; 052 053import java.math.BigDecimal; 054import java.util.UUID; 055 056import org.apache.commons.lang3.*; 057import org.apache.commons.lang3.builder.HashCodeBuilder; 058import org.hl7.fhir.instance.model.api.*; 059 060import ca.uhn.fhir.model.api.annotation.DatatypeDef; 061 062/** 063 * This class represents the logical identity for a resource, or as much of that 064 * identity is known. In FHIR, every resource must have a "logical ID" which is 065 * defined by the FHIR specification as: 066 * <p> 067 * <code> 068 * Any combination of upper or lower case ASCII letters ('A'..'Z', and 'a'..'z', numerals ('0'..'9'), '-' and '.', with a length limit of 64 characters. (This might be an integer, an un-prefixed OID, UUID or any other identifier pattern that meets these constraints.) 069 * </code> 070 * </p> 071 * <p> 072 * This class contains that logical ID, and can optionally also contain a 073 * relative or absolute URL representing the resource identity. For example, the 074 * following are all valid values for IdType, and all might represent the same 075 * resource: 076 * </p> 077 * <ul> 078 * <li><code>123</code> (just a resource's ID)</li> 079 * <li><code>Patient/123</code> (a relative identity)</li> 080 * <li><code>http://example.com/Patient/123 (an absolute identity)</code></li> 081 * <li> 082 * <code>http://example.com/Patient/123/_history/1 (an absolute identity with a version id)</code> 083 * </li> 084 * <li> 085 * <code>Patient/123/_history/1 (a relative identity with a version id)</code> 086 * </li> 087 * </ul> 088 * <p> 089 * Note that the 64 character 090 * limit applies only to the ID portion ("123" in the examples above). 091 * </p> 092 * <p> 093 * In most situations, you only need to populate the resource's ID (e.g. 094 * <code>123</code>) in resources you are constructing and the encoder will 095 * infer the rest from the context in which the object is being used. On the 096 * other hand, the parser will always try to populate the complete absolute 097 * identity on objects it creates as a convenience. 098 * </p> 099 * <p> 100 * Regex for ID: [a-z0-9\-\.]{1,64} 101 * </p> 102 */ 103@DatatypeDef(name = "id", profileOf=StringType.class) 104public final class IdType extends UriType implements IPrimitiveType<String>, IIdType { 105 public static final String URN_PREFIX = "urn:"; 106 107 /** 108 * This is the maximum length for the ID 109 */ 110 public static final int MAX_LENGTH = 64; // maximum length 111 112 private static final long serialVersionUID = 2L; 113 private String myBaseUrl; 114 private boolean myHaveComponentParts; 115 private String myResourceType; 116 private String myUnqualifiedId; 117 private String myUnqualifiedVersionId; 118 119 /** 120 * Create a new empty ID 121 */ 122 public IdType() { 123 super(); 124 } 125 126 /** 127 * Create a new ID, using a BigDecimal input. Uses 128 * {@link BigDecimal#toPlainString()} to generate the string representation. 129 */ 130 public IdType(BigDecimal thePid) { 131 if (thePid != null) { 132 setValue(toPlainStringWithNpeThrowIfNeeded(thePid)); 133 } else { 134 setValue(null); 135 } 136 } 137 138 /** 139 * Create a new ID using a long 140 */ 141 public IdType(long theId) { 142 setValue(Long.toString(theId)); 143 } 144 145 /** 146 * Create a new ID using a string. This String may contain a simple ID (e.g. 147 * "1234") or it may contain a complete URL 148 * (http://example.com/fhir/Patient/1234). 149 * 150 * <p> 151 * <b>Description</b>: A whole number in the range 0 to 2^64-1 (optionally 152 * represented in hex), a uuid, an oid, or any other combination of lowercase 153 * letters, numerals, "-" and ".", with a length limit of 36 characters. 154 * </p> 155 * <p> 156 * regex: [a-z0-9\-\.]{1,36} 157 * </p> 158 */ 159 public IdType(String theValue) { 160 setValue(theValue); 161 } 162 163 /** 164 * Constructor 165 * 166 * @param theResourceType 167 * The resource type (e.g. "Patient") 168 * @param theIdPart 169 * The ID (e.g. "123") 170 */ 171 public IdType(String theResourceType, BigDecimal theIdPart) { 172 this(theResourceType, toPlainStringWithNpeThrowIfNeeded(theIdPart)); 173 } 174 175 /** 176 * Constructor 177 * 178 * @param theResourceType 179 * The resource type (e.g. "Patient") 180 * @param theIdPart 181 * The ID (e.g. "123") 182 */ 183 public IdType(String theResourceType, Long theIdPart) { 184 this(theResourceType, toPlainStringWithNpeThrowIfNeeded(theIdPart)); 185 } 186 187 /** 188 * Constructor 189 * 190 * @param theResourceType 191 * The resource type (e.g. "Patient") 192 * @param theId 193 * The ID (e.g. "123") 194 */ 195 public IdType(String theResourceType, String theId) { 196 this(theResourceType, theId, null); 197 } 198 199 /** 200 * Constructor 201 * 202 * @param theResourceType 203 * The resource type (e.g. "Patient") 204 * @param theId 205 * The ID (e.g. "123") 206 * @param theVersionId 207 * The version ID ("e.g. "456") 208 */ 209 public IdType(String theResourceType, String theId, String theVersionId) { 210 this(null, theResourceType, theId, theVersionId); 211 } 212 213 /** 214 * Constructor 215 * 216 * @param theBaseUrl 217 * The server base URL (e.g. "http://example.com/fhir") 218 * @param theResourceType 219 * The resource type (e.g. "Patient") 220 * @param theId 221 * The ID (e.g. "123") 222 * @param theVersionId 223 * The version ID ("e.g. "456") 224 */ 225 public IdType(String theBaseUrl, String theResourceType, String theId, String theVersionId) { 226 myBaseUrl = theBaseUrl; 227 myResourceType = theResourceType; 228 myUnqualifiedId = theId; 229 myUnqualifiedVersionId = StringUtils.defaultIfBlank(theVersionId, null); 230 myHaveComponentParts = true; 231 if (isBlank(myBaseUrl) && isBlank(myResourceType) && isBlank(myUnqualifiedId) && isBlank(myUnqualifiedVersionId)) { 232 myHaveComponentParts = false; 233 } 234 } 235 236 /** 237 * Creates an ID based on a given URL 238 */ 239 public IdType(UriType theUrl) { 240 setValue(theUrl.getValueAsString()); 241 } 242 243 public void applyTo(IBaseResource theResource) { 244 if (theResource == null) { 245 throw new NullPointerException("theResource can not be null"); 246 } else { 247 theResource.setId(new IdType(getValue())); 248 } 249 } 250 251 /** 252 * @deprecated Use {@link #getIdPartAsBigDecimal()} instead (this method was 253 * deprocated because its name is ambiguous) 254 */ 255 @Deprecated 256 public BigDecimal asBigDecimal() { 257 return getIdPartAsBigDecimal(); 258 } 259 260 @Override 261 public IdType copy() { 262 return new IdType(getValue()); 263 } 264 265 @Override 266 public boolean equals(Object theArg0) { 267 if (!(theArg0 instanceof IdType)) { 268 return false; 269 } 270 return StringUtils.equals(getValueAsString(), ((IdType)theArg0).getValueAsString()); 271 } 272 273 /** 274 * Returns true if this IdType matches the given IdType in terms of resource 275 * type and ID, but ignores the URL base 276 */ 277 @SuppressWarnings("deprecation") 278 public boolean equalsIgnoreBase(IdType theId) { 279 if (theId == null) { 280 return false; 281 } 282 if (theId.isEmpty()) { 283 return isEmpty(); 284 } 285 return ObjectUtils.equals(getResourceType(), theId.getResourceType()) 286 && ObjectUtils.equals(getIdPart(), theId.getIdPart()) 287 && ObjectUtils.equals(getVersionIdPart(), theId.getVersionIdPart()); 288 } 289 290 /** 291 * Returns the portion of this resource ID which corresponds to the server 292 * base URL. For example given the resource ID 293 * <code>http://example.com/fhir/Patient/123</code> the base URL would be 294 * <code>http://example.com/fhir</code>. 295 * <p> 296 * This method may return null if the ID contains no base (e.g. "Patient/123") 297 * </p> 298 */ 299 @Override 300 public String getBaseUrl() { 301 return myBaseUrl; 302 } 303 304 /** 305 * Returns only the logical ID part of this ID. For example, given the ID 306 * "http://example,.com/fhir/Patient/123/_history/456", this method would 307 * return "123". 308 */ 309 @Override 310 public String getIdPart() { 311 return myUnqualifiedId; 312 } 313 314 /** 315 * Returns the unqualified portion of this ID as a big decimal, or 316 * <code>null</code> if the value is null 317 * 318 * @throws NumberFormatException 319 * If the value is not a valid BigDecimal 320 */ 321 public BigDecimal getIdPartAsBigDecimal() { 322 String val = getIdPart(); 323 if (isBlank(val)) { 324 return null; 325 } 326 return new BigDecimal(val); 327 } 328 329 /** 330 * Returns the unqualified portion of this ID as a {@link Long}, or 331 * <code>null</code> if the value is null 332 * 333 * @throws NumberFormatException 334 * If the value is not a valid Long 335 */ 336 @Override 337 public Long getIdPartAsLong() { 338 String val = getIdPart(); 339 if (isBlank(val)) { 340 return null; 341 } 342 return Long.parseLong(val); 343 } 344 345 @Override 346 public String getResourceType() { 347 return myResourceType; 348 } 349 350 /** 351 * Returns the value of this ID. Note that this value may be a fully qualified 352 * URL, a relative/partial URL, or a simple ID. Use {@link #getIdPart()} to 353 * get just the ID portion. 354 * 355 * @see #getIdPart() 356 */ 357 @Override 358 public String getValue() { 359 String retVal = super.getValue(); 360 if (retVal == null && myHaveComponentParts) { 361 362 if (isLocal() || isUrn()) { 363 return myUnqualifiedId; 364 } 365 366 StringBuilder b = new StringBuilder(); 367 if (isNotBlank(myBaseUrl)) { 368 b.append(myBaseUrl); 369 if (myBaseUrl.charAt(myBaseUrl.length() - 1) != '/') { 370 b.append('/'); 371 } 372 } 373 374 if (isNotBlank(myResourceType)) { 375 b.append(myResourceType); 376 } 377 378 if (b.length() > 0 && isNotBlank(myUnqualifiedId)) { 379 b.append('/'); 380 } 381 382 if (isNotBlank(myUnqualifiedId)) { 383 b.append(myUnqualifiedId); 384 } else if (isNotBlank(myUnqualifiedVersionId)) { 385 b.append('/'); 386 } 387 388 if (isNotBlank(myUnqualifiedVersionId)) { 389 b.append('/'); 390 b.append("_history"); 391 b.append('/'); 392 b.append(myUnqualifiedVersionId); 393 } 394 retVal = b.toString(); 395 super.setValue(retVal); 396 } 397 return retVal; 398 } 399 400 @Override 401 public String getValueAsString() { 402 return getValue(); 403 } 404 405 @Override 406 public String getVersionIdPart() { 407 return myUnqualifiedVersionId; 408 } 409 410 public Long getVersionIdPartAsLong() { 411 if (!hasVersionIdPart()) { 412 return null; 413 } else { 414 return Long.parseLong(getVersionIdPart()); 415 } 416 } 417 418 /** 419 * Returns true if this ID has a base url 420 * 421 * @see #getBaseUrl() 422 */ 423 public boolean hasBaseUrl() { 424 return isNotBlank(myBaseUrl); 425 } 426 427 @Override 428 public int hashCode() { 429 HashCodeBuilder b = new HashCodeBuilder(); 430 b.append(getValueAsString()); 431 return b.toHashCode(); 432 } 433 434 @Override 435 public boolean hasIdPart() { 436 return isNotBlank(getIdPart()); 437 } 438 439 @Override 440 public boolean hasResourceType() { 441 return isNotBlank(myResourceType); 442 } 443 444 @Override 445 public boolean hasVersionIdPart() { 446 return isNotBlank(getVersionIdPart()); 447 } 448 449 /** 450 * Returns <code>true</code> if this ID contains an absolute URL (in other 451 * words, a URL starting with "http://" or "https://" 452 */ 453 @Override 454 public boolean isAbsolute() { 455 if (StringUtils.isBlank(getValue())) { 456 return false; 457 } 458 return isUrlAbsolute(getValue()); 459 } 460 461 @Override 462 public boolean isEmpty() { 463 return super.isEmpty() && isBlank(getValue()); 464 } 465 466 @Override 467 public boolean isIdPartValid() { 468 String id = getIdPart(); 469 if (StringUtils.isBlank(id)) { 470 return false; 471 } 472 if (id.length() > 64) { 473 return false; 474 } 475 for (int i = 0; i < id.length(); i++) { 476 char nextChar = id.charAt(i); 477 if (nextChar >= 'a' && nextChar <= 'z') { 478 continue; 479 } 480 if (nextChar >= 'A' && nextChar <= 'Z') { 481 continue; 482 } 483 if (nextChar >= '0' && nextChar <= '9') { 484 continue; 485 } 486 if (nextChar == '-' || nextChar == '.') { 487 continue; 488 } 489 return false; 490 } 491 return true; 492 } 493 494 /** 495 * Returns <code>true</code> if the unqualified ID is a valid {@link Long} 496 * value (in other words, it consists only of digits) 497 */ 498 @Override 499 public boolean isIdPartValidLong() { 500 return isValidLong(getIdPart()); 501 } 502 503 /** 504 * Returns <code>true</code> if the ID is a local reference (in other words, 505 * it begins with the '#' character) 506 */ 507 @Override 508 public boolean isLocal() { 509 return defaultString(myUnqualifiedId).startsWith("#"); 510 } 511 512 public boolean isUrn() { 513 return defaultString(myUnqualifiedId).startsWith(URN_PREFIX); 514 } 515 516 @Override 517 public boolean isVersionIdPartValidLong() { 518 return isValidLong(getVersionIdPart()); 519 } 520 521 /** 522 * Set the value 523 * 524 * <p> 525 * <b>Description</b>: A whole number in the range 0 to 2^64-1 (optionally 526 * represented in hex), a uuid, an oid, or any other combination of lowercase 527 * letters, numerals, "-" and ".", with a length limit of 36 characters. 528 * </p> 529 * <p> 530 * regex: [a-z0-9\-\.]{1,36} 531 * </p> 532 */ 533 @Override 534 public IdType setValue(String theValue) { 535 // TODO: add validation 536 super.setValue(theValue); 537 538 myHaveComponentParts = false; 539 540 if (StringUtils.isBlank(theValue)) { 541 myBaseUrl = null; 542 super.setValue(null); 543 myUnqualifiedId = null; 544 myUnqualifiedVersionId = null; 545 myResourceType = null; 546 } else if (theValue.charAt(0) == '#' && theValue.length() > 1) { 547 super.setValue(theValue); 548 myBaseUrl = null; 549 myUnqualifiedId = theValue; 550 myUnqualifiedVersionId = null; 551 myResourceType = null; 552 myHaveComponentParts = true; 553 } else if (theValue.startsWith(URN_PREFIX)) { 554 myBaseUrl = null; 555 myUnqualifiedId = theValue; 556 myUnqualifiedVersionId = null; 557 myResourceType = null; 558 myHaveComponentParts = true; 559 } else { 560 int vidIndex = theValue.indexOf("/_history/"); 561 int idIndex; 562 if (vidIndex != -1) { 563 myUnqualifiedVersionId = theValue.substring(vidIndex + "/_history/".length()); 564 idIndex = theValue.lastIndexOf('/', vidIndex - 1); 565 myUnqualifiedId = theValue.substring(idIndex + 1, vidIndex); 566 } else { 567 idIndex = theValue.lastIndexOf('/'); 568 myUnqualifiedId = theValue.substring(idIndex + 1); 569 myUnqualifiedVersionId = null; 570 } 571 572 myBaseUrl = null; 573 if (idIndex <= 0) { 574 myResourceType = null; 575 } else { 576 int typeIndex = theValue.lastIndexOf('/', idIndex - 1); 577 if (typeIndex == -1) { 578 myResourceType = theValue.substring(0, idIndex); 579 } else { 580 if (typeIndex > 0 && '/' == theValue.charAt(typeIndex - 1)) { 581 typeIndex = theValue.indexOf('/', typeIndex + 1); 582 } 583 if (typeIndex >= idIndex) { 584 // e.g. http://example.org/foo 585 // 'foo' was the id but we're making that the resource type. Nullify the id part because we don't have an id. 586 // Also set null value to the super.setValue() and enable myHaveComponentParts so it forces getValue() to properly 587 // recreate the url 588 myResourceType = myUnqualifiedId; 589 myUnqualifiedId = null; 590 super.setValue(null); 591 myHaveComponentParts = true; 592 } else { 593 myResourceType = theValue.substring(typeIndex + 1, idIndex); 594 } 595 596 if (typeIndex > 4) { 597 myBaseUrl = theValue.substring(0, typeIndex); 598 } 599 600 } 601 } 602 603 } 604 return this; 605 } 606 607 /** 608 * Set the value 609 * 610 * <p> 611 * <b>Description</b>: A whole number in the range 0 to 2^64-1 (optionally 612 * represented in hex), a uuid, an oid, or any other combination of lowercase 613 * letters, numerals, "-" and ".", with a length limit of 36 characters. 614 * </p> 615 * <p> 616 * regex: [a-z0-9\-\.]{1,36} 617 * </p> 618 */ 619 @Override 620 public void setValueAsString(String theValue) { 621 setValue(theValue); 622 } 623 624 @Override 625 public String toString() { 626 return getValue(); 627 } 628 629 /** 630 * Returns a new IdType containing this IdType's values but with no server 631 * base URL if one is present in this IdType. For example, if this IdType 632 * contains the ID "http://foo/Patient/1", this method will return a new 633 * IdType containing ID "Patient/1". 634 */ 635 @Override 636 public IdType toUnqualified() { 637 if (isLocal() || isUrn()) { 638 return new IdType(getValueAsString()); 639 } 640 return new IdType(getResourceType(), getIdPart(), getVersionIdPart()); 641 } 642 643 @Override 644 public IdType toUnqualifiedVersionless() { 645 if (isLocal() || isUrn()) { 646 return new IdType(getValueAsString()); 647 } 648 return new IdType(getResourceType(), getIdPart()); 649 } 650 651 @Override 652 public IdType toVersionless() { 653 if (isLocal() || isUrn()) { 654 return new IdType(getValueAsString()); 655 } 656 return new IdType(getBaseUrl(), getResourceType(), getIdPart(), null); 657 } 658 659 @Override 660 public IdType withResourceType(String theResourceName) { 661 if (isLocal() || isUrn()) { 662 return new IdType(getValueAsString()); 663 } 664 return new IdType(theResourceName, getIdPart(), getVersionIdPart()); 665 } 666 667 /** 668 * Returns a view of this ID as a fully qualified URL, given a server base and 669 * resource name (which will only be used if the ID does not already contain 670 * those respective parts). Essentially, because IdType can contain either a 671 * complete URL or a partial one (or even jut a simple ID), this method may be 672 * used to translate into a complete URL. 673 * 674 * @param theServerBase 675 * The server base (e.g. "http://example.com/fhir") 676 * @param theResourceType 677 * The resource name (e.g. "Patient") 678 * @return A fully qualified URL for this ID (e.g. 679 * "http://example.com/fhir/Patient/1") 680 */ 681 @Override 682 public IdType withServerBase(String theServerBase, String theResourceType) { 683 if (isLocal() || isUrn()) { 684 return new IdType(getValueAsString()); 685 } 686 return new IdType(theServerBase, theResourceType, getIdPart(), getVersionIdPart()); 687 } 688 689 /** 690 * Creates a new instance of this ID which is identical, but refers to the 691 * specific version of this resource ID noted by theVersion. 692 * 693 * @param theVersion The actual version string, e.g. "1". If theVersion is blank or null, returns the same as {@link #toVersionless()}} 694 * @return A new instance of IdType which is identical, but refers to the 695 * specific version of this resource ID noted by theVersion. 696 */ 697 @Override 698 public IdType withVersion(String theVersion) { 699 if (isBlank(theVersion)) { 700 return toVersionless(); 701 } 702 703 if (isLocal() || isUrn()) { 704 return new IdType(getValueAsString()); 705 } 706 707 String existingValue = getValue(); 708 709 int i = existingValue.indexOf("_history"); 710 String value; 711 if (i > 1) { 712 value = existingValue.substring(0, i - 1); 713 } else { 714 value = existingValue; 715 } 716 717 return new IdType(value + '/' + "_history" + '/' + theVersion); 718 } 719 720 private static boolean isUrlAbsolute(String theValue) { 721 String value = theValue.toLowerCase(); 722 return value.startsWith("http://") || value.startsWith("https://"); 723 } 724 725 private static boolean isValidLong(String id) { 726 if (StringUtils.isBlank(id)) { 727 return false; 728 } 729 for (int i = 0; i < id.length(); i++) { 730 if (Character.isDigit(id.charAt(i)) == false) { 731 return false; 732 } 733 } 734 return true; 735 } 736 737 /** 738 * Construct a new ID with with form "urn:uuid:[UUID]" where [UUID] is a new, 739 * randomly created UUID generated by {@link UUID#randomUUID()} 740 */ 741 public static IdType newRandomUuid() { 742 return new IdType("urn:uuid:" + UUID.randomUUID().toString()); 743 } 744 745 /** 746 * Retrieves the ID from the given resource instance 747 */ 748 public static IdType of(IBaseResource theResouce) { 749 if (theResouce == null) { 750 throw new NullPointerException("theResource can not be null"); 751 } else { 752 IIdType retVal = theResouce.getIdElement(); 753 if (retVal == null) { 754 return null; 755 } else if (retVal instanceof IdType) { 756 return (IdType) retVal; 757 } else { 758 return new IdType(retVal.getValue()); 759 } 760 } 761 } 762 763 private static String toPlainStringWithNpeThrowIfNeeded(BigDecimal theIdPart) { 764 if (theIdPart == null) { 765 throw new NullPointerException("BigDecimal ID can not be null"); 766 } 767 return theIdPart.toPlainString(); 768 } 769 770 private static String toPlainStringWithNpeThrowIfNeeded(Long theIdPart) { 771 if (theIdPart == null) { 772 throw new NullPointerException("Long ID can not be null"); 773 } 774 return theIdPart.toString(); 775 } 776 777 public String fhirType() { 778 return "id"; 779 } 780 781 @Override 782 public IIdType setParts(String theBaseUrl, String theResourceType, String theIdPart, String theVersionIdPart) { 783 if (isNotBlank(theVersionIdPart)) { 784 Validate.notBlank(theResourceType, "If theVersionIdPart is populated, theResourceType and theIdPart must be populated"); 785 Validate.notBlank(theIdPart, "If theVersionIdPart is populated, theResourceType and theIdPart must be populated"); 786 } 787 if (isNotBlank(theBaseUrl) && isNotBlank(theIdPart)) { 788 Validate.notBlank(theResourceType, "If theBaseUrl is populated and theIdPart is populated, theResourceType must be populated"); 789 } 790 791 setValue(null); 792 793 myBaseUrl = theBaseUrl; 794 myResourceType = theResourceType; 795 myUnqualifiedId = theIdPart; 796 myUnqualifiedVersionId = StringUtils.defaultIfBlank(theVersionIdPart, null); 797 myHaveComponentParts = true; 798 799 return this; 800 } 801 802}