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