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