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 java.io.Serializable;
033import java.util.ArrayList;
034import java.util.HashMap;
035import java.util.List;
036import java.util.Map;
037
038import org.hl7.fhir.instance.model.api.IBase;
039import org.hl7.fhir.exceptions.FHIRException;
040import org.hl7.fhir.utilities.xhtml.XhtmlNode;
041
042public abstract class Base implements Serializable, IBase {
043
044  /**
045   * User appended data items - allow users to add extra information to the class
046   */
047  private Map<String, Object> userData;
048
049  /**
050   * Round tracking xml comments for testing convenience
051   */
052  private List<String> formatCommentsPre;
053
054  /**
055   * Round tracking xml comments for testing convenience
056   */
057  private List<String> formatCommentsPost;
058
059  public Object getUserData(String name) {
060    if (userData == null)
061      return null;
062    return userData.get(name);
063  }
064
065  public void setUserData(String name, Object value) {
066    if (userData == null)
067      userData = new HashMap<String, Object>();
068    userData.put(name, value);
069  }
070
071  public void setUserDataINN(String name, Object value) {
072    if (value == null)
073      return;
074
075    if (userData == null)
076      userData = new HashMap<String, Object>();
077    userData.put(name, value);
078  }
079
080  public boolean hasUserData(String name) {
081    if (userData == null)
082      return false;
083    else
084      return userData.containsKey(name);
085  }
086
087  public String getUserString(String name) {
088    return (String) getUserData(name);
089  }
090
091  public int getUserInt(String name) {
092    if (!hasUserData(name))
093      return 0;
094    return (Integer) getUserData(name);
095  }
096
097  public boolean hasFormatComment() {
098    return (formatCommentsPre != null && !formatCommentsPre.isEmpty())
099        || (formatCommentsPost != null && !formatCommentsPost.isEmpty());
100  }
101
102  public List<String> getFormatCommentsPre() {
103    if (formatCommentsPre == null)
104      formatCommentsPre = new ArrayList<String>();
105    return formatCommentsPre;
106  }
107
108  public List<String> getFormatCommentsPost() {
109    if (formatCommentsPost == null)
110      formatCommentsPost = new ArrayList<String>();
111    return formatCommentsPost;
112  }
113
114  // these 2 allow evaluation engines to get access to primitive values
115  public boolean isPrimitive() {
116    return false;
117  }
118
119  public String primitiveValue() {
120    return null;
121  }
122
123  public abstract String fhirType();
124
125  public boolean hasType(String... name) {
126    String t = fhirType();
127    for (String n : name)
128      if (n.equals(t))
129        return true;
130    return false;
131  }
132
133  protected abstract void listChildren(List<Property> result);
134
135  public void setProperty(String name, Base value) throws FHIRException {
136    throw new FHIRException("Attempt to set unknown property " + name);
137  }
138
139  public Base addChild(String name) throws FHIRException {
140    throw new FHIRException("Attempt to add child with unknown name " + name);
141  }
142
143  /**
144   * Supports iterating the children elements in some generic processor or browser
145   * All defined children will be listed, even if they have no value on this
146   * instance
147   * 
148   * Note that the actual content of primitive or xhtml elements is not iterated
149   * explicitly. To find these, the processing code must recognise the element as
150   * a primitive, typecast the value to a {@link Type}, and examine the value
151   * 
152   * @return a list of all the children defined for this element
153   */
154  public List<Property> children() {
155    List<Property> result = new ArrayList<Property>();
156    listChildren(result);
157    return result;
158  }
159
160  public Property getChildByName(String name) {
161    List<Property> children = new ArrayList<Property>();
162    listChildren(children);
163    for (Property c : children)
164      if (c.getName().equals(name))
165        return c;
166    return null;
167  }
168
169  public List<Base> listChildrenByName(String name) {
170    List<Property> children = new ArrayList<Property>();
171    listChildren(children);
172    if (name.equals("*")) {
173      List<Base> res = new ArrayList<Base>();
174      for (Property p : children) {
175        res.addAll(p.getValues());
176      }
177      return res;
178    } else {
179      for (Property c : children)
180        if (c.getName().equals(name) || (c.getName().equals(name + "[x]")))
181          return c.getValues();
182    }
183    return new ArrayList<Base>();
184  }
185
186  public boolean isEmpty() {
187    return true; // userData does not count
188  }
189
190  public boolean equalsDeep(Base other) {
191    return other != null;
192  }
193
194  public boolean equalsShallow(Base other) {
195    return other != null;
196  }
197
198  public static boolean compareDeep(List<? extends Base> e1, List<? extends Base> e2, boolean allowNull) {
199    if (noList(e1) && noList(e2) && allowNull)
200      return true;
201    if (noList(e1) || noList(e2))
202      return false;
203    if (e1.size() != e2.size())
204      return false;
205    for (int i = 0; i < e1.size(); i++) {
206      if (!compareDeep(e1.get(i), e2.get(i), allowNull))
207        return false;
208    }
209    return true;
210  }
211
212  private static boolean noList(List<? extends Base> list) {
213    return list == null || list.isEmpty();
214  }
215
216  public static boolean compareDeep(Base e1, Base e2, boolean allowNull) {
217    if (e1 == null && e2 == null && allowNull)
218      return true;
219    if (e1 == null || e2 == null)
220      return false;
221    if (e2.isMetadataBased() && !e1.isMetadataBased()) // respect existing order for debugging consistency; outcome must
222                                                       // be the same either way
223      return e2.equalsDeep(e1);
224    else
225      return e1.equalsDeep(e2);
226  }
227
228  public static boolean compareDeep(XhtmlNode div1, XhtmlNode div2, boolean allowNull) {
229    if (div1 == null && div2 == null && allowNull)
230      return true;
231    if (div1 == null || div2 == null)
232      return false;
233    return div1.equalsDeep(div2);
234  }
235
236  public static boolean compareValues(List<? extends PrimitiveType> e1, List<? extends PrimitiveType> e2,
237      boolean allowNull) {
238    if (e1 == null && e2 == null && allowNull)
239      return true;
240    if (e1 == null || e2 == null)
241      return false;
242    if (e1.size() != e2.size())
243      return false;
244    for (int i = 0; i < e1.size(); i++) {
245      if (!compareValues(e1.get(i), e2.get(i), allowNull))
246        return false;
247    }
248    return true;
249  }
250
251  public static boolean compareValues(PrimitiveType e1, PrimitiveType e2, boolean allowNull) {
252    if (e1 == null && e2 == null && allowNull)
253      return true;
254    if (e1 == null || e2 == null)
255      return false;
256    return e1.equalsShallow(e2);
257  }
258
259  // -- converters for property setters
260
261  public BooleanType castToBoolean(Base b) throws FHIRException {
262    if (b instanceof BooleanType)
263      return (BooleanType) b;
264    else
265      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a Boolean");
266  }
267
268  public IntegerType castToInteger(Base b) throws FHIRException {
269    if (b instanceof IntegerType)
270      return (IntegerType) b;
271    else
272      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a Integer");
273  }
274
275  public DecimalType castToDecimal(Base b) throws FHIRException {
276    if (b instanceof DecimalType)
277      return (DecimalType) b;
278    else
279      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a Decimal");
280  }
281
282  public Base64BinaryType castToBase64Binary(Base b) throws FHIRException {
283    if (b instanceof Base64BinaryType)
284      return (Base64BinaryType) b;
285    else
286      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a Base64Binary");
287  }
288
289  public InstantType castToInstant(Base b) throws FHIRException {
290    if (b instanceof InstantType)
291      return (InstantType) b;
292    else
293      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a Instant");
294  }
295
296  public StringType castToString(Base b) throws FHIRException {
297    if (b instanceof StringType)
298      return (StringType) b;
299    else
300      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a String");
301  }
302
303  public UriType castToUri(Base b) throws FHIRException {
304    if (b instanceof UriType)
305      return (UriType) b;
306    else
307      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a Uri");
308  }
309
310  public DateType castToDate(Base b) throws FHIRException {
311    if (b instanceof DateType)
312      return (DateType) b;
313    else
314      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a Date");
315  }
316
317  public DateTimeType castToDateTime(Base b) throws FHIRException {
318    if (b instanceof DateTimeType)
319      return (DateTimeType) b;
320    else
321      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a DateTime");
322  }
323
324  public TimeType castToTime(Base b) throws FHIRException {
325    if (b instanceof TimeType)
326      return (TimeType) b;
327    else
328      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a Time");
329  }
330
331  public CodeType castToCode(Base b) throws FHIRException {
332    if (b instanceof CodeType)
333      return (CodeType) b;
334    else
335      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a Code");
336  }
337
338  public OidType castToOid(Base b) throws FHIRException {
339    if (b instanceof OidType)
340      return (OidType) b;
341    else
342      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a Oid");
343  }
344
345  public IdType castToId(Base b) throws FHIRException {
346    if (b instanceof IdType)
347      return (IdType) b;
348    else
349      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a Id");
350  }
351
352  public UnsignedIntType castToUnsignedInt(Base b) throws FHIRException {
353    if (b instanceof UnsignedIntType)
354      return (UnsignedIntType) b;
355    else
356      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a UnsignedInt");
357  }
358
359  public PositiveIntType castToPositiveInt(Base b) throws FHIRException {
360    if (b instanceof PositiveIntType)
361      return (PositiveIntType) b;
362    else
363      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a PositiveInt");
364  }
365
366  public MarkdownType castToMarkdown(Base b) throws FHIRException {
367    if (b instanceof MarkdownType)
368      return (MarkdownType) b;
369    else
370      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a Markdown");
371  }
372
373  public Annotation castToAnnotation(Base b) throws FHIRException {
374    if (b instanceof Annotation)
375      return (Annotation) b;
376    else
377      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to an Annotation");
378  }
379
380  public Attachment castToAttachment(Base b) throws FHIRException {
381    if (b instanceof Attachment)
382      return (Attachment) b;
383    else
384      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to an Attachment");
385  }
386
387  public Identifier castToIdentifier(Base b) throws FHIRException {
388    if (b instanceof Identifier)
389      return (Identifier) b;
390    else
391      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to an Identifier");
392  }
393
394  public CodeableConcept castToCodeableConcept(Base b) throws FHIRException {
395    if (b instanceof CodeableConcept)
396      return (CodeableConcept) b;
397    else if (b instanceof CodeType) {
398      CodeableConcept cc = new CodeableConcept();
399      cc.addCoding().setCode(((CodeType) b).asStringValue());
400      return cc;
401    } else
402      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a CodeableConcept");
403  }
404
405  public Coding castToCoding(Base b) throws FHIRException {
406    if (b instanceof Coding)
407      return (Coding) b;
408    else
409      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a Coding");
410  }
411
412  public Quantity castToQuantity(Base b) throws FHIRException {
413    if (b instanceof Quantity)
414      return (Quantity) b;
415    else
416      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to an Quantity");
417  }
418
419  public Money castToMoney(Base b) throws FHIRException {
420    if (b instanceof Money)
421      return (Money) b;
422    else
423      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to an Money");
424  }
425
426  public Duration castToDuration(Base b) throws FHIRException {
427    if (b instanceof Duration)
428      return (Duration) b;
429    else
430      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to an Duration");
431  }
432
433  public SimpleQuantity castToSimpleQuantity(Base b) throws FHIRException {
434    if (b instanceof SimpleQuantity)
435      return (SimpleQuantity) b;
436    else if (b instanceof Quantity) {
437      Quantity q = (Quantity) b;
438      SimpleQuantity sq = new SimpleQuantity();
439      sq.setValueElement(q.getValueElement());
440      sq.setComparatorElement(q.getComparatorElement());
441      sq.setUnitElement(q.getUnitElement());
442      sq.setSystemElement(q.getSystemElement());
443      sq.setCodeElement(q.getCodeElement());
444      return sq;
445    } else
446      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to an SimpleQuantity");
447  }
448
449  public Range castToRange(Base b) throws FHIRException {
450    if (b instanceof Range)
451      return (Range) b;
452    else
453      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a Range");
454  }
455
456  public Period castToPeriod(Base b) throws FHIRException {
457    if (b instanceof Period)
458      return (Period) b;
459    else
460      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a Period");
461  }
462
463  public Ratio castToRatio(Base b) throws FHIRException {
464    if (b instanceof Ratio)
465      return (Ratio) b;
466    else
467      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a Ratio");
468  }
469
470  public SampledData castToSampledData(Base b) throws FHIRException {
471    if (b instanceof SampledData)
472      return (SampledData) b;
473    else
474      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a SampledData");
475  }
476
477  public Signature castToSignature(Base b) throws FHIRException {
478    if (b instanceof Signature)
479      return (Signature) b;
480    else
481      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a Signature");
482  }
483
484  public HumanName castToHumanName(Base b) throws FHIRException {
485    if (b instanceof HumanName)
486      return (HumanName) b;
487    else
488      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a HumanName");
489  }
490
491  public Address castToAddress(Base b) throws FHIRException {
492    if (b instanceof Address)
493      return (Address) b;
494    else
495      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a Address");
496  }
497
498  public ContactPoint castToContactPoint(Base b) throws FHIRException {
499    if (b instanceof ContactPoint)
500      return (ContactPoint) b;
501    else
502      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a ContactPoint");
503  }
504
505  public Timing castToTiming(Base b) throws FHIRException {
506    if (b instanceof Timing)
507      return (Timing) b;
508    else
509      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a Timing");
510  }
511
512  public Reference castToReference(Base b) throws FHIRException {
513    if (b instanceof Reference)
514      return (Reference) b;
515    else
516      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a Reference");
517  }
518
519  public Meta castToMeta(Base b) throws FHIRException {
520    if (b instanceof Meta)
521      return (Meta) b;
522    else
523      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a Meta");
524  }
525
526  public Extension castToExtension(Base b) throws FHIRException {
527    if (b instanceof Extension)
528      return (Extension) b;
529    else
530      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a Extension");
531  }
532
533  public Resource castToResource(Base b) throws FHIRException {
534    if (b instanceof Resource)
535      return (Resource) b;
536    else
537      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a Resource");
538  }
539
540  public Narrative castToNarrative(Base b) throws FHIRException {
541    if (b instanceof Narrative)
542      return (Narrative) b;
543    else
544      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a Narrative");
545  }
546
547  public ElementDefinition castToElementDefinition(Base b) throws FHIRException {
548    if (b instanceof ElementDefinition)
549      return (ElementDefinition) b;
550    else
551      throw new FHIRException("Unable to convert a " + b.getClass().getName() + " to a ElementDefinition");
552  }
553
554  protected boolean isMetadataBased() {
555    return false;
556  }
557
558  public static boolean equals(String v1, String v2) {
559    if (v1 == null && v2 == null)
560      return true;
561    else if (v1 == null || v2 == null)
562      return false;
563    else
564      return v1.equals(v2);
565  }
566
567}