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