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