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