001package org.hl7.fhir.dstu2016may.metamodel; 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 032 033 034import java.util.ArrayList; 035import java.util.HashSet; 036import java.util.List; 037import java.util.Set; 038 039import org.hl7.fhir.dstu2016may.model.Base; 040import org.hl7.fhir.exceptions.FHIRException; 041import org.hl7.fhir.utilities.Utilities; 042import org.hl7.fhir.utilities.xhtml.XhtmlNode; 043 044/** 045 * This class represents the reference model of FHIR 046 * 047 * A resource is nothing but a set of elements, where every element has a 048 * name, maybe a stated type, maybe an id, and either a value or child elements 049 * (one or the other, or both (but not neither if it's null) 050 * 051 * @author Grahame Grieve 052 * 053 */ 054public class Element extends Base { 055 056 public enum SpecialElement { 057 CONTAINED, BUNDLE_ENTRY; 058 } 059 060 private List<String> comments;// not relevant for production, but useful in documentation 061 private String name; 062 private String type; 063 private String value; 064 private int index = -1; 065 private List<Element> children; 066 private Property property; 067 private int line; 068 private int col; 069 private SpecialElement special; 070 private XhtmlNode xhtml; // if this is populated, then value will also hold the string representation 071 072 public Element(String name) { 073 super(); 074 this.name = name; 075 } 076 077 public Element(String name, Property property) { 078 super(); 079 this.name = name; 080 this.property = property; 081 } 082 083 public Element(String name, Property property, String type, String value) { 084 super(); 085 this.name = name; 086 this.property = property; 087 this.type = type; 088 this.value = value; 089 } 090 091 public void updateProperty(Property property, SpecialElement special) { 092 this.property = property; 093 this.special = special; 094 } 095 096 public SpecialElement getSpecial() { 097 return special; 098 } 099 100 public String getName() { 101 return name; 102 } 103 104 public String getType() { 105 if (type == null) 106 return property.getType(name); 107 else 108 return type; 109 } 110 111 public String getValue() { 112 return value; 113 } 114 115 public boolean hasChildren() { 116 return !(children == null || children.isEmpty()); 117 } 118 119 public List<Element> getChildren() { 120 if (children == null) 121 children = new ArrayList<Element>(); 122 return children; 123 } 124 125 public boolean hasComments() { 126 return !(comments == null || comments.isEmpty()); 127 } 128 129 public List<String> getComments() { 130 if (comments == null) 131 comments = new ArrayList<String>(); 132 return comments; 133 } 134 135 public Property getProperty() { 136 return property; 137 } 138 139 public void setValue(String value) { 140 this.value = value; 141 } 142 143 public void setType(String type) { 144 this.type = type; 145 146 } 147 148 public boolean hasValue() { 149 return value != null; 150 } 151 152 public List<Element> getChildrenByName(String name) { 153 List<Element> res = new ArrayList<Element>(); 154 if (hasChildren()) { 155 for (Element child : children) 156 if (name.equals(child.getName())) 157 res.add(child); 158 } 159 return res; 160 } 161 162 public void numberChildren() { 163 if (children == null) 164 return; 165 166 String last = ""; 167 int index = 0; 168 for (Element child : children) { 169 if (child.getProperty().isList()) { 170 if (last.equals(child.getName())) { 171 index++; 172 } else { 173 last = child.getName(); 174 index = 0; 175 } 176 child.index = index; 177 } else { 178 child.index = -1; 179 } 180 child.numberChildren(); 181 } 182 } 183 184 public int getIndex() { 185 return index; 186 } 187 188 public boolean hasIndex() { 189 return index > -1; 190 } 191 192 public void setIndex(int index) { 193 this.index = index; 194 } 195 196 public String getChildValue(String name) { 197 if (children == null) 198 return null; 199 for (Element child : children) { 200 if (name.equals(child.getName())) 201 return child.getValue(); 202 } 203 return null; 204 } 205 206 public List<Element> getChildren(String name) { 207 List<Element> res = new ArrayList<Element>(); 208 for (Element child : children) { 209 if (name.equals(child.getName())) 210 res.add(child); 211 } 212 return res; 213 } 214 215 public boolean hasType() { 216 if (type == null) 217 return property.hasType(name); 218 else 219 return true; 220 } 221 222 @Override 223 public String fhirType() { 224 return getType(); 225 } 226 227 @Override 228 public Base[] getProperty(int hash, String name, boolean checkValid) throws FHIRException { 229 if (isPrimitive() && (hash == "value".hashCode()) && !Utilities.noString(value)) { 230 String tn = getType(); 231 throw new Error("not done yet"); 232 } 233 234 List<Base> result = new ArrayList<Base>(); 235 for (Element child : children) { 236 if (child.getName().equals(name)) 237 result.add(child); 238 if (child.getName().startsWith(name) && child.getProperty().isChoice() && child.getProperty().getName().equals(name+"[x]")) 239 result.add(child); 240 } 241 if (result.isEmpty() && checkValid) { 242// throw new FHIRException("not determined yet"); 243 } 244 return result.toArray(new Base[result.size()]); 245 } 246 247 @Override 248 protected void listChildren( 249 List<org.hl7.fhir.dstu2016may.model.Property> result) { 250 // TODO Auto-generated method stub 251 252 } 253 254 @Override 255 public boolean isPrimitive() { 256 return type != null ? ParserBase.isPrimitive(type) : property.isPrimitive(name); 257 } 258 259 @Override 260 public boolean hasPrimitiveValue() { 261 return property.isPrimitive(name) || property.IsLogicalAndHasPrimitiveValue(name); 262 } 263 264 265 @Override 266 public String primitiveValue() { 267 if (isPrimitive()) 268 return value; 269 else { 270 if (hasPrimitiveValue()) { 271 for (Element c : children) { 272 if (c.getName().equals("value")) 273 return c.primitiveValue(); 274 } 275 } 276 return null; 277 } 278 } 279 280 // for the validator 281 public int line() { 282 return line; 283 } 284 285 public int col() { 286 return col; 287 } 288 289 public Element markLocation(int line, int col) { 290 this.line = line; 291 this.col = col; 292 return this; 293 } 294 295 public Element getNamedChild(String name) { 296 if (children == null) 297 return null; 298 Element result = null; 299 for (Element child : children) { 300 if (child.getName().equals(name)) { 301 if (result == null) 302 result = child; 303 else 304 throw new Error("Attempt to read a single element when there is more than one present ("+name+")"); 305 } 306 } 307 return result; 308 } 309 310 public void getNamedChildren(String name, List<Element> list) { 311 if (children != null) 312 for (Element child : children) 313 if (child.getName().equals(name)) 314 list.add(child); 315 } 316 317 public String getNamedChildValue(String name) { 318 Element child = getNamedChild(name); 319 return child == null ? null : child.value; 320 } 321 322 public void getNamedChildrenWithWildcard(String string, List<Element> values) { 323 throw new Error("not done yet"); 324 } 325 326 327 public XhtmlNode getXhtml() { 328 return xhtml; 329 } 330 331 public Element setXhtml(XhtmlNode xhtml) { 332 this.xhtml = xhtml; 333 return this; 334 } 335 336 @Override 337 public boolean equalsDeep(Base other) { 338 if (!super.equalsDeep(other)) 339 return false; 340 if (isPrimitive() && other.isPrimitive()) 341 return primitiveValue().equals(other.primitiveValue()); 342 if (isPrimitive() || other.isPrimitive()) 343 return false; 344 Set<String> processed = new HashSet<String>(); 345 for (org.hl7.fhir.dstu2016may.model.Property p : children()) { 346 String name = p.getName(); 347 processed.add(name); 348 org.hl7.fhir.dstu2016may.model.Property o = other.getChildByName(name); 349 if (!equalsDeep(p, o)) 350 return false; 351 } 352 for (org.hl7.fhir.dstu2016may.model.Property p : children()) { 353 String name = p.getName(); 354 if (!processed.contains(name)) { 355 org.hl7.fhir.dstu2016may.model.Property o = other.getChildByName(name); 356 if (!equalsDeep(p, o)) 357 return false; 358 } 359 } 360 return true; 361 } 362 363 private boolean equalsDeep(org.hl7.fhir.dstu2016may.model.Property p, org.hl7.fhir.dstu2016may.model.Property o) { 364 if (o == null || p == null) 365 return false; 366 if (p.getValues().size() != o.getValues().size()) 367 return false; 368 for (int i = 0; i < p.getValues().size(); i++) 369 if (!Base.compareDeep(p.getValues().get(i), o.getValues().get(i), true)) 370 return false; 371 return true; 372 } 373 374 @Override 375 public boolean equalsShallow(Base other) { 376 if (!super.equalsShallow(other)) 377 return false; 378 if (isPrimitive() && other.isPrimitive()) 379 return primitiveValue().equals(other.primitiveValue()); 380 if (isPrimitive() || other.isPrimitive()) 381 return false; 382 return true; //? 383 } 384 385}