
001package org.hl7.fhir.r5.renderers.utils; 002 003import java.io.IOException; 004import java.util.ArrayList; 005import java.util.Collection; 006import java.util.List; 007import java.util.Locale; 008 009import org.hl7.fhir.r5.context.ContextUtilities; 010import org.hl7.fhir.r5.elementmodel.Element; 011import org.hl7.fhir.r5.model.Base; 012import org.hl7.fhir.r5.model.DataType; 013import org.hl7.fhir.r5.model.Resource; 014import org.hl7.fhir.utilities.MarkedToMoveToAdjunctPackage; 015import org.hl7.fhir.utilities.xhtml.XhtmlNode; 016 017/** 018 * This class is used to walk through the resources when rendering, whether 019 * the resource is a native resource or loaded by the element model 020 */ 021@MarkedToMoveToAdjunctPackage 022public abstract class ResourceWrapper { 023 024 public enum ElementKind { 025 PrimitiveType, 026 DataType, 027 BackboneElement, 028 ContainedResource, 029 InlineResource, 030 BundleEntry, 031 IndependentResource 032 } 033 034 public static class NamedResourceWrapperList { 035 private String name; 036 private String url; // for extension definitions 037 private List<ResourceWrapper> values = new ArrayList<ResourceWrapper>(); 038 039 public NamedResourceWrapperList(String name) { 040 super(); 041 this.name = name; 042 } 043 044 public NamedResourceWrapperList(String name, String url) { 045 super(); 046 this.name = name; 047 this.url = url; 048 } 049 050 public String getName() { 051 return name; 052 } 053 054 public String getUrl() { 055 return url; 056 } 057 058 public List<ResourceWrapper> getValues() { 059 return values; 060 } 061// public ElementDefinition getPropertyDefinition() { 062// return values.isEmpty() ? null : values.get(0).getPropertyDefinition(); 063// } 064// public StructureDefinition getClassDefinition() { 065// return values.isEmpty() ? null : values.get(0).getClassDefinition(); 066// } 067 } 068 069 protected ContextUtilities contextUtils; 070 protected ResourceWrapper parent; 071 protected String name; // null at root 072 protected int index; // -1 if not repeating 073 protected ElementKind kind; 074 075 protected List<ResourceWrapper> children; 076 077 // -- Constructors ------------------------------------------------------------------ 078 079 protected ResourceWrapper() { 080 // TODO Auto-generated constructor stub 081 } 082 083 public static ResourceWrapper forResource(ContextUtilities contextUtils, Resource resource) { 084 ResourceWrapperNative self = new ResourceWrapperNative(); 085 self.contextUtils = contextUtils; 086 self.parent = null; 087 self.name = null; 088 self.index = -1; 089 self.kind = ElementKind.IndependentResource; 090 self.element = resource; 091 return self; 092 } 093 094 public static ResourceWrapper forResource(ContextUtilities contextUtils, Element resource) { 095 ResourceWrapperModel self = new ResourceWrapperModel(); 096 self.contextUtils = contextUtils; 097 self.parent = null; 098 self.name = null; 099 self.index = -1; 100 self.kind = ElementKind.IndependentResource; 101 self.model = resource; 102 return self; 103 } 104 105 public static ResourceWrapper forResource(RenderingContext context, Resource resource) { 106 return forResource(context.getContextUtilities(), resource); 107 } 108 109 public static ResourceWrapper forResource(RenderingContext context, Element resource) { 110 return forResource(context.getContextUtilities(), resource); 111 } 112 113 public static ResourceWrapper forType(ContextUtilities contextUtils, Element resource) { 114 ResourceWrapperModel self = new ResourceWrapperModel(); 115 self.contextUtils = contextUtils; 116 self.parent = null; 117 self.name = null; 118 self.index = -1; 119 self.kind = ElementKind.DataType; 120 self.model = resource; 121 return self; 122 } 123 124 public static ResourceWrapper forType(ContextUtilities contextUtils, DataType type) { 125 ResourceWrapperNative self = new ResourceWrapperNative(); 126 self.contextUtils = contextUtils; 127 self.parent = null; 128 self.name = null; 129 self.index = -1; 130 self.kind = null; 131 self.element = type; 132 return self; 133 } 134 135 public static ResourceWrapper forType(ContextUtilities contextUtils, ResourceWrapper parent, DataType type) { 136 ResourceWrapperNative self = new ResourceWrapperNative(); 137 self.contextUtils = contextUtils; 138 self.parent = parent; 139 self.name = null; 140 self.index = -1; 141 self.kind = null; 142 self.element = type; 143 return self; 144 } 145 146 147 public String path() { 148 if (parent == null) { 149 return fhirType(); 150 } else { 151 return parent.path()+"." + (index == -1 ? name : name+"["+index+"]"); 152 } 153 } 154 155 protected String basePath() { 156 if (parent == null || this.isResource()) { 157 return this.fhirType(); 158 } else { 159 return parent.basePath()+"."+name; 160 } 161 } 162 163 public ElementKind kind() { 164 return kind; 165 } 166 167 public String name() { 168 return name; 169 } 170 171 public int index() { 172 return index; 173 } 174 175 public boolean isPrimitive(String name) { 176 ResourceWrapper child = child(name); 177 return child != null && child.isPrimitive(); 178 } 179 180 public boolean hasPrimitiveValue(String name) { 181 ResourceWrapper child = child(name); 182 return child != null && child.hasPrimitiveValue(); 183 } 184 185 public String primitiveValue(String name) { 186 ResourceWrapper child = child(name); 187 return child == null ? null : child.primitiveValue(); 188 } 189 190 public String primitiveValueMN(String... names) { 191 ResourceWrapper child = childMN(names); 192 return child == null ? null : child.primitiveValue(); 193 } 194 195 public String firstPrimitiveValue(String name) { 196 ResourceWrapper child = firstChild(name); 197 return child == null ? null : child.primitiveValue(); 198 } 199 200 private void loadChildren() { 201 if (children == null) { 202 children = new ArrayList<>(); 203 loadTheChildren(); 204 } 205 } 206 207 208 public List<ResourceWrapper> children() { 209 loadChildren(); 210 return children; 211 } 212 213 public List<NamedResourceWrapperList> childrenInGroups() { 214 loadChildren(); 215 List<NamedResourceWrapperList> list = new ArrayList<ResourceWrapper.NamedResourceWrapperList>(); 216 for (ResourceWrapper e : children) { 217 NamedResourceWrapperList nl = null; 218 for (NamedResourceWrapperList t : list) { 219 if (t.name.equals(e.name())) { 220 nl = t; 221 } 222 } 223 if (nl == null) { 224 nl = new NamedResourceWrapperList(e.name()); 225 list.add(nl); 226 } 227 nl.values.add(e); 228 } 229 return list; 230 } 231 232 public List<ResourceWrapper> children(String name) { 233 loadChildren(); 234 List<ResourceWrapper> list = new ArrayList<ResourceWrapper>(); 235 for (ResourceWrapper e : children) { 236 if (name.equals(e.name())) { 237 list.add(e); 238 } 239 } 240 return list; 241 } 242 243 /** 244 * For when an item has been renamed - find by any of the names 245 * @param name 246 * @return 247 */ 248 public List<ResourceWrapper> childrenMN(String... names) { 249 loadChildren(); 250 List<ResourceWrapper> list = new ArrayList<ResourceWrapper>(); 251 for (ResourceWrapper e : children) { 252 for (String name : names) { 253 if (name.equals(e.name())) { 254 list.add(e); 255 } 256 } 257 } 258 return list; 259 } 260 261 public ResourceWrapper child(String name) { 262 loadChildren(); 263 264 ResourceWrapper res = null; 265 266 for (ResourceWrapper e : children) { 267 if (name.equals(e.name()) || (name+"[x]").equals(e.name())) { 268 if (res == null) { 269 res = e; 270 } else { 271 throw new Error("Duplicated element '"+name+"' @ '"+path()+"'"); 272 } 273 } 274 } 275 return res; 276 } 277 278 /** 279 * For when an item has been renamed - find by any of the names 280 * @param names 281 * @return 282 */ 283 public ResourceWrapper childMN(String... names) { 284 loadChildren(); 285 286 ResourceWrapper res = null; 287 288 for (ResourceWrapper e : children) { 289 for (String name : names) { 290 if (name.equals(e.name()) || (name+"[x]").equals(e.name())) { 291 if (res == null) { 292 res = e; 293 } else { 294 throw new Error("Duplicated element '"+name+"' @ '"+path()+"'"); 295 } 296 } 297 } 298 } 299 return res; 300 } 301 302 public boolean has(String name) { 303 loadChildren(); 304 for (ResourceWrapper e : children) { 305 if (name.equals(e.name()) || (name+"[x]").equals(e.name())) { 306 return true; 307 } 308 } 309 return false; 310 } 311 312 public boolean hasMN(String... names) { 313 loadChildren(); 314 for (ResourceWrapper e : children) { 315 for (String name : names) { 316 if (name.equals(e.name()) || (name+"[x]").equals(e.name())) { 317 return true; 318 } 319 } 320 } 321 return false; 322 } 323 324 public ResourceWrapper resource() { 325 ResourceWrapper e = this.parent; 326 while (e != null && !e.isResource()) { 327 e = e.parent; 328 } 329 return e; 330 } 331 332 public boolean hasChildren() { 333 loadChildren(); 334 return !children.isEmpty(); 335 } 336 337 public boolean hasExtension(String url) { 338 loadChildren(); 339 for (ResourceWrapper e : children) { 340 if ("Extension".equals(e.fhirType()) && url.equals(e.primitiveValue("url"))) { 341 return true; 342 } 343 } 344 return false; 345 } 346 347 public ResourceWrapper extension(String url) { 348 ResourceWrapper res = null; 349 loadChildren(); 350 for (ResourceWrapper e : children) { 351 if ("Extension".equals(e.fhirType()) && url.equals(e.primitiveValue("url"))) { 352 if (res == null) { 353 res = e; 354 } else { 355 throw new Error("Duplicated extension '"+url+"' @ '"+path()+"'"); 356 } 357 } 358 } 359 return res; 360 } 361 362 public ResourceWrapper extensionValue(String url) { 363 ResourceWrapper res = null; 364 loadChildren(); 365 for (ResourceWrapper e : children) { 366 if ("Extension".equals(e.fhirType()) && url.equals(e.primitiveValue("url"))) { 367 if (res == null) { 368 res = e.child("value"); 369 } else { 370 throw new Error("Duplicated extension '"+url+"' @ '"+path()+"'"); 371 } 372 } 373 } 374 return res; 375 } 376 377 public List<ResourceWrapper> extensions(String url) { 378 List<ResourceWrapper> res = new ArrayList<ResourceWrapper>(); 379 loadChildren(); 380 for (ResourceWrapper e : children) { 381 if ("Extension".equals(e.fhirType()) && url.equals(e.primitiveValue("url"))) { 382 res.add(e); 383 } 384 } 385 return res; 386 } 387 388 public List<ResourceWrapper> extensions() { 389 List<ResourceWrapper> res = new ArrayList<ResourceWrapper>(); 390 loadChildren(); 391 for (ResourceWrapper e : children) { 392 if ("Extension".equals(e.fhirType())) { 393 res.add(e); 394 } 395 } 396 return res; 397 } 398 399 public List<ResourceWrapper> extensionValues(String url) { 400 List<ResourceWrapper> res = new ArrayList<ResourceWrapper>(); 401 loadChildren(); 402 for (ResourceWrapper e : children) { 403 if ("Extension".equals(e.fhirType()) && url.equals(e.primitiveValue("url"))) { 404 if (e.has("value")) { 405 res.add(e.child("value")); 406 } 407 } 408 } 409 return res; 410 } 411 412 public abstract Resource getResourceNative(); 413 public abstract boolean canHaveNarrative(); 414 public abstract XhtmlNode getNarrative(); 415 public abstract boolean hasNarrative(); 416 public abstract void setNarrative(XhtmlNode x, String status, boolean multiLangMode, Locale locale, boolean isPretty) throws IOException; 417 public abstract String getId(); 418 419 public void markLanguage(XhtmlNode x, Locale locale) { 420 x.setAttribute("lang", locale.toLanguageTag()); 421 x.setAttribute("xml:lang", locale.toLanguageTag()); 422 x.addTag(0, "hr"); 423 x.addTag(0, "p").b().tx(locale.getDisplayName()); 424 x.addTag(0, "hr"); 425 } 426 427 428 public boolean matches(ResourceWrapper b) { 429 if (isEmpty() || b.isEmpty()) { 430 return isEmpty() && b.isEmpty(); 431 } else { 432 if (hasPrimitiveValue() || b.hasPrimitiveValue()) { 433 if (!hasPrimitiveValue() || !b.hasPrimitiveValue() || !primitiveValue().equals(b.primitiveValue())) { 434 return false; 435 } 436 } 437 if (children().size() != b.children().size()) { 438 return false; 439 } else { 440 for (int i = 0; i < children().size(); i++) { 441 if (!children().get(i).matches(b.children().get(i))) { 442 return false; 443 } 444 } 445 return true; 446 } 447 } 448 } 449 450 public String extensionString(String url) { 451 ResourceWrapper re = extensionValue(url); 452 return re == null ? null : re.primitiveValue(); 453 } 454 455 public boolean isEmpty() { 456 if (hasChildren()) { 457 for (ResourceWrapper c : children) { 458 if (!c.isEmpty()) { 459 return false; 460 } 461 } 462 } 463 return !isPrimitive() || !hasPrimitiveValue(); 464 } 465 466 467 public ResourceWrapper getResourceWrapper() { 468 ResourceWrapper focus = this; 469 while (focus != null && !focus.isResource()) { 470 focus = focus.parent; 471 } 472 return focus; 473 } 474 475 public ResourceWrapper firstChild(String name) { 476 List<ResourceWrapper> list = children(name); 477 return list.size() == 0 ? null : list.get(0); 478 } 479 480 public ContextUtilities getContextUtilities() { 481 return contextUtils; 482 } 483 484 public String getScopedId() { 485 if (!isResource()) { 486 return null; 487 } else { 488 String res = getId(); 489 if (parent != null) { 490 res = parent.getResourceWrapper().getScopedId()+"/"+getId(); 491 } 492 return res; 493 } 494 } 495 496 public ResourceWrapper parent() { 497 return parent; 498 } 499 500 public ResourceWrapper getContained(String id) { 501 if (isResource()) { 502 List<ResourceWrapper> contained = children("contained"); 503 for (ResourceWrapper e : contained) { 504 if (id.equals(e.getId())) { 505 return e; 506 } 507 } 508 } 509 return null; 510 } 511 512 513 public abstract String getCodeSystemUri(); 514 public abstract boolean hasFormatComment(); 515 public abstract Collection<String> getFormatCommentsPre(); 516 public abstract XhtmlNode getXhtml(); 517 public abstract Base getBase(); 518 public abstract String getWebPath(); 519 public abstract boolean isDirect(); 520 protected abstract void loadTheChildren(); 521 public abstract String fhirVersion(); 522 public abstract String fhirType(); 523 public abstract boolean isPrimitive(); 524 public abstract boolean hasPrimitiveValue(); 525 public abstract String primitiveValue(); 526 public abstract boolean isResource(); 527 public abstract boolean hasUserData(String name); 528 public abstract Object getUserData(String name); 529 530 531}