001package ca.uhn.fhir.model.api; 002 003/* 004 * #%L 005 * HAPI FHIR - Core Library 006 * %% 007 * Copyright (C) 2014 - 2016 University Health Network 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 */ 022import static org.apache.commons.lang3.StringUtils.isNotBlank; 023 024import java.io.Serializable; 025import java.util.ArrayList; 026import java.util.Collections; 027import java.util.Date; 028import java.util.List; 029import java.util.Map; 030 031import org.apache.commons.lang3.StringUtils; 032import org.hl7.fhir.instance.model.api.IAnyResource; 033import org.hl7.fhir.instance.model.api.IPrimitiveType; 034 035import ca.uhn.fhir.model.base.composite.BaseCodingDt; 036import ca.uhn.fhir.model.primitive.DecimalDt; 037import ca.uhn.fhir.model.primitive.IdDt; 038import ca.uhn.fhir.model.primitive.InstantDt; 039import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum; 040import ca.uhn.fhir.model.valueset.BundleEntryTransactionMethodEnum; 041import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; 042 043/** 044 * Keys in this map refer to <b>resource metadata keys</b>, which are keys used to access information about specific resource instances that live outside of the resource body. Typically, these are 045 * data elements which are sent/receieved in HTTP Headers along with read/create resource requests, or properties which can be found in bundle entries. 046 * <p> 047 * To access or set resource metadata values, every resource has a metadata map, and this class provides convenient getters/setters for interacting with that map. For example, to get a resource's 048 * {@link #UPDATED} value, which is the "last updated" time for that resource, use the following code: 049 * </p> 050 * <p> 051 * <code>InstantDt updated = ResourceMetadataKeyEnum.UPDATED.get(resource);</code> 052 * <p> 053 * <p> 054 * To set this value, use the following: 055 * </p> 056 * <p> 057 * <code>InstantDt update = new InstantDt("2011-01-02T11:22:33.0000Z"); // populate with the actual time<br> 058 * ResourceMetadataKeyEnum.UPDATED.put(resource, update);</code> 059 * </p> 060 * <p> 061 * Note that this class is not a Java Enum, and can therefore be extended (this is why it is not actually an Enum). Users of HAPI-FHIR are able to create their own classes extending this class to 062 * define their own keys for storage in resource metadata if needed. 063 * </p> 064 */ 065public abstract class ResourceMetadataKeyEnum<T> implements Serializable { 066 067 private static final long serialVersionUID = 1L; 068 069 /** 070 * If present and populated with a date/time (as an instance of {@link InstantDt}), this value is an indication that the resource is in the deleted state. This key is only used in a limited number 071 * of scenarios, such as POSTing transaction bundles to a server, or returning resource history. 072 * <p> 073 * Values for this key are of type <b>{@link InstantDt}</b> 074 * </p> 075 */ 076 public static final ResourceMetadataKeySupportingAnyResource<InstantDt, IPrimitiveType<Date>> DELETED_AT = new ResourceMetadataKeySupportingAnyResource<InstantDt, IPrimitiveType<Date>>("DELETED_AT") { 077 private static final long serialVersionUID = 1L; 078 079 @Override 080 public InstantDt get(IResource theResource) { 081 return getInstantFromMetadataOrNullIfNone(theResource.getResourceMetadata(), DELETED_AT); 082 } 083 084 @Override 085 public void put(IResource theResource, InstantDt theObject) { 086 theResource.getResourceMetadata().put(DELETED_AT, theObject); 087 } 088 089 @SuppressWarnings("unchecked") 090 @Override 091 public IPrimitiveType<Date> get(IAnyResource theResource) { 092 return (IPrimitiveType<Date>) theResource.getUserData(DELETED_AT.name()); 093 } 094 095 @Override 096 public void put(IAnyResource theResource, IPrimitiveType<Date> theObject) { 097 theResource.setUserData(DELETED_AT.name(), theObject); 098 } 099 }; 100 101 /** 102 * Denotes the search score which a given resource should match in a transaction. See the FHIR transaction definition for information about this. Corresponds to the value in 103 * <code>Bundle.entry.score</code> in a Bundle resource. 104 * <p> 105 * Note that search URL is only used in FHIR DSTU2 and later. 106 * </p> 107 * <p> 108 * Values for this key are of type <b>{@link DecimalDt}</b> 109 * </p> 110 */ 111 public static final ResourceMetadataKeyEnum<DecimalDt> ENTRY_SCORE = new ResourceMetadataKeyEnum<DecimalDt>("ENTRY_SCORE") { 112 private static final long serialVersionUID = 1L; 113 114 @Override 115 public DecimalDt get(IResource theResource) { 116 return getDecimalFromMetadataOrNullIfNone(theResource.getResourceMetadata(), ENTRY_SCORE); 117 } 118 119 @Override 120 public void put(IResource theResource, DecimalDt theObject) { 121 theResource.getResourceMetadata().put(ENTRY_SCORE, theObject); 122 } 123 }; 124 125 /** 126 * If present and populated with a {@link BundleEntrySearchModeEnum}, contains the "bundle entry search mode", which is the value of the status field in the Bundle entry containing this resource. 127 * The value for this key corresponds to field <code>Bundle.entry.search.mode</code>. This value can be set to provide a status value of "include" for included resources being returned by a 128 * server, or to "match" to indicate that the resource was returned because it matched the given search criteria. 129 * <p> 130 * Note that status is only used in FHIR DSTU2 and later. 131 * </p> 132 * <p> 133 * Values for this key are of type <b>{@link BundleEntrySearchModeEnum}</b> 134 * </p> 135 */ 136 public static final ResourceMetadataKeySupportingAnyResource<BundleEntrySearchModeEnum, String> ENTRY_SEARCH_MODE = new ResourceMetadataKeySupportingAnyResource<BundleEntrySearchModeEnum, String>("ENTRY_SEARCH_MODE") { 137 private static final long serialVersionUID = 1L; 138 @Override 139 public BundleEntrySearchModeEnum get(IResource theResource) { 140 return getEnumFromMetadataOrNullIfNone(theResource.getResourceMetadata(), ENTRY_SEARCH_MODE, BundleEntrySearchModeEnum.class, BundleEntrySearchModeEnum.VALUESET_BINDER); 141 } 142 143 @Override 144 public void put(IResource theResource, BundleEntrySearchModeEnum theObject) { 145 theResource.getResourceMetadata().put(ENTRY_SEARCH_MODE, theObject); 146 } 147 148 @Override 149 public String get(IAnyResource theResource) { 150 return (String) theResource.getUserData(ENTRY_SEARCH_MODE.name()); 151 } 152 153 @Override 154 public void put(IAnyResource theResource, String theObject) { 155 theResource.setUserData(ENTRY_SEARCH_MODE.name(), theObject); 156 } 157 }; 158 159 /** 160 * If present and populated with a {@link BundleEntryTransactionMethodEnum}, contains the "bundle entry transaction operation", which is the value of the status field in the Bundle entry 161 * containing this resource. The value for this key corresponds to field <code>Bundle.entry.transaction.operation</code>. This value can be set in resources being transmitted to a server to 162 * provide a status value of "create" or "update" to indicate behaviour the server should observe. It may also be set to similar values (or to "noop") in resources being returned by a server as a 163 * result of a transaction to indicate to the client what operation was actually performed. 164 * <p> 165 * Note that status is only used in FHIR DSTU2 and later. 166 * </p> 167 * <p> 168 * Values for this key are of type <b>{@link BundleEntryTransactionMethodEnum}</b> 169 * </p> 170 */ 171 public static final ResourceMetadataKeySupportingAnyResource<BundleEntryTransactionMethodEnum, String> ENTRY_TRANSACTION_METHOD = new ResourceMetadataKeySupportingAnyResource<BundleEntryTransactionMethodEnum, String>( 172 "ENTRY_TRANSACTION_OPERATION") { 173 private static final long serialVersionUID = 1L; 174 175 @Override 176 public BundleEntryTransactionMethodEnum get(IResource theResource) { 177 return getEnumFromMetadataOrNullIfNone(theResource.getResourceMetadata(), ENTRY_TRANSACTION_METHOD, BundleEntryTransactionMethodEnum.class, 178 BundleEntryTransactionMethodEnum.VALUESET_BINDER); 179 } 180 181 @Override 182 public void put(IResource theResource, BundleEntryTransactionMethodEnum theObject) { 183 theResource.getResourceMetadata().put(ENTRY_TRANSACTION_METHOD, theObject); 184 } 185 186 @Override 187 public String get(IAnyResource theResource) { 188 return (String) theResource.getUserData(ENTRY_TRANSACTION_METHOD.name()); 189 } 190 191 @Override 192 public void put(IAnyResource theResource, String theObject) { 193 theResource.setUserData(ENTRY_TRANSACTION_METHOD.name(), theObject); 194 } 195 196 }; 197 198 /** 199 * If present and populated with a string, provides the "alternate link" (the link element in the bundle entry with <code>rel="alternate"</code>). Server implementations may populate this with a 200 * complete URL, in which case the URL will be placed as-is in the bundle. They may alternately specify a resource relative URL (e.g. "Patient/1243") in which case the server will convert this to 201 * an absolute URL at runtime. 202 * <p> 203 * Values for this key are of type <b>{@link String}</b> 204 * </p> 205 */ 206 public static final ResourceMetadataKeyEnum<String> LINK_ALTERNATE = new ResourceMetadataKeyEnum<String>("LINK_ALTERNATE") { 207 private static final long serialVersionUID = 1L; 208 @Override 209 public String get(IResource theResource) { 210 return getStringFromMetadataOrNullIfNone(theResource.getResourceMetadata(), LINK_ALTERNATE); 211 } 212 213 @Override 214 public void put(IResource theResource, String theObject) { 215 theResource.getResourceMetadata().put(LINK_ALTERNATE, theObject); 216 } 217 }; 218 219 /** 220 * If present and populated with a string, provides the "search link" (the link element in the bundle entry with <code>rel="search"</code>). Server implementations may populate this with a 221 * complete URL, in which case the URL will be placed as-is in the bundle. They may alternately specify a resource relative URL (e.g. "Patient?name=tester") in which case the server will convert 222 * this to an absolute URL at runtime. 223 * <p> 224 * Values for this key are of type <b>{@link String}</b> 225 * </p> 226 */ 227 public static final ResourceMetadataKeyEnum<String> LINK_SEARCH = new ResourceMetadataKeyEnum<String>("LINK_SEARCH") { 228 private static final long serialVersionUID = 1L; 229 @Override 230 public String get(IResource theResource) { 231 return getStringFromMetadataOrNullIfNone(theResource.getResourceMetadata(), LINK_SEARCH); 232 } 233 234 @Override 235 public void put(IResource theResource, String theObject) { 236 theResource.getResourceMetadata().put(LINK_SEARCH, theObject); 237 } 238 }; 239 240 /** 241 * The value for this key represents a previous ID used to identify this resource. This key is currently only used internally during transaction method processing. 242 * <p> 243 * Values for this key are of type <b>{@link IdDt}</b> 244 * </p> 245 */ 246 public static final ResourceMetadataKeyEnum<IdDt> PREVIOUS_ID = new ResourceMetadataKeyEnum<IdDt>("PREVIOUS_ID") { 247 private static final long serialVersionUID = 1L; 248 @Override 249 public IdDt get(IResource theResource) { 250 return getIdFromMetadataOrNullIfNone(theResource.getResourceMetadata(), PREVIOUS_ID); 251 } 252 253 @Override 254 public void put(IResource theResource, IdDt theObject) { 255 theResource.getResourceMetadata().put(PREVIOUS_ID, theObject); 256 } 257 }; 258 259 /** 260 * The value for this key represents a {@link List} of profile IDs that this resource claims to conform to. 261 * 262 * <p> 263 * Values for this key are of type <b>List<IdDt></b>. Note that the returned list is <i>unmodifiable</i>, so you need to create a new list and call <code>put</code> to change its value. 264 * </p> 265 */ 266 public static final ResourceMetadataKeyEnum<List<IdDt>> PROFILES = new ResourceMetadataKeyEnum<List<IdDt>>("PROFILES") { 267 private static final long serialVersionUID = 1L; 268 @Override 269 public List<IdDt> get(IResource theResource) { 270 return getIdListFromMetadataOrNullIfNone(theResource.getResourceMetadata(), PROFILES); 271 } 272 273 @Override 274 public void put(IResource theResource, List<IdDt> theObject) { 275 theResource.getResourceMetadata().put(PROFILES, theObject); 276 } 277 }; 278 279 /** 280 * The value for this key is the bundle entry <b>Published</b> time. This is defined by FHIR as "Time resource copied into the feed", which is generally best left to the current time. 281 * <p> 282 * Values for this key are of type <b>{@link InstantDt}</b> 283 * </p> 284 * <p> 285 * <b>Server Note</b>: In servers, it is generally advisable to leave this value <code>null</code>, in which case the server will substitute the current time automatically. 286 * </p> 287 * 288 * @see InstantDt 289 */ 290 public static final ResourceMetadataKeyEnum<InstantDt> PUBLISHED = new ResourceMetadataKeyEnum<InstantDt>("PUBLISHED") { 291 private static final long serialVersionUID = 1L; 292 @Override 293 public InstantDt get(IResource theResource) { 294 return getInstantFromMetadataOrNullIfNone(theResource.getResourceMetadata(), PUBLISHED); 295 } 296 297 @Override 298 public void put(IResource theResource, InstantDt theObject) { 299 theResource.getResourceMetadata().put(PUBLISHED, theObject); 300 } 301 }; 302 303 public static final ResourceMetadataKeyEnum<List<BaseCodingDt>> SECURITY_LABELS = new ResourceMetadataKeyEnum<List<BaseCodingDt>>("SECURITY_LABELS") { 304 private static final long serialVersionUID = 1L; 305 @Override 306 public List<BaseCodingDt> get(IResource resource) { 307 Object obj = resource.getResourceMetadata().get(SECURITY_LABELS); 308 if (obj == null) { 309 return null; 310 } else { 311 try { 312 @SuppressWarnings("unchecked") 313 List<BaseCodingDt> securityLabels = (List<BaseCodingDt>) obj; 314 if (securityLabels.isEmpty()) 315 return null; 316 else 317 return securityLabels; 318 } catch (ClassCastException e) { 319 throw new InternalErrorException("Found an object of type '" + obj.getClass().getCanonicalName() + "' in resource metadata for key SECURITY_LABELS - Expected " 320 + BaseCodingDt.class.getCanonicalName()); 321 322 } 323 324 } 325 } 326 327 @Override 328 public void put(IResource iResource, List<BaseCodingDt> labels) { 329 iResource.getResourceMetadata().put(SECURITY_LABELS, labels); 330 } 331 332 }; 333 334 /** 335 * The value for this key is the list of tags associated with this resource 336 * <p> 337 * Values for this key are of type <b>{@link TagList}</b> 338 * </p> 339 * 340 * @see TagList 341 */ 342 public static final ResourceMetadataKeyEnum<TagList> TAG_LIST = new ResourceMetadataKeyEnum<TagList>("TAG_LIST") { 343 private static final long serialVersionUID = 1L; 344 @Override 345 public TagList get(IResource theResource) { 346 Object retValObj = theResource.getResourceMetadata().get(TAG_LIST); 347 if (retValObj == null) { 348 return null; 349 } else if (retValObj instanceof TagList) { 350 if (((TagList) retValObj).isEmpty()) { 351 return null; 352 } else { 353 return (TagList) retValObj; 354 } 355 } 356 throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + TAG_LIST.name() + " - Expected " 357 + TagList.class.getCanonicalName()); 358 } 359 360 @Override 361 public void put(IResource theResource, TagList theObject) { 362 theResource.getResourceMetadata().put(TAG_LIST, theObject); 363 } 364 }; 365 366 /** 367 * If present and populated with a string (as an instance of {@link String}), this value contains the title for this resource, as supplied in any bundles containing the resource. 368 * <p> 369 * Values for this key are of type <b>{@link String}</b> 370 * </p> 371 */ 372 public static final ResourceMetadataKeyEnum<String> TITLE = new ResourceMetadataKeyEnum<String>("TITLE") { 373 private static final long serialVersionUID = 1L; 374 @Override 375 public String get(IResource theResource) { 376 return getStringFromMetadataOrNullIfNone(theResource.getResourceMetadata(), TITLE); 377 } 378 379 @Override 380 public void put(IResource theResource, String theObject) { 381 theResource.getResourceMetadata().put(TITLE, theObject); 382 } 383 }; 384 385 /** 386 * The value for this key is the bundle entry <b>Updated</b> time. This is defined by FHIR as "Last Updated for resource". This value is also used for populating the "Last-Modified" header in the 387 * case of methods that return a single resource (read, vread, etc.) 388 * <p> 389 * Values for this key are of type <b>{@link InstantDt}</b> 390 * </p> 391 * 392 * @see InstantDt 393 */ 394 public static final ResourceMetadataKeyEnum<InstantDt> UPDATED = new ResourceMetadataKeyEnum<InstantDt>("UPDATED") { 395 private static final long serialVersionUID = 1L; 396 @Override 397 public InstantDt get(IResource theResource) { 398 return getInstantFromMetadataOrNullIfNone(theResource.getResourceMetadata(), UPDATED); 399 } 400 401 @Override 402 public void put(IResource theResource, InstantDt theObject) { 403 theResource.getResourceMetadata().put(UPDATED, theObject); 404 } 405 }; 406 407 /** 408 * The value for this key is the version ID of the resource object. 409 * <p> 410 * Values for this key are of type <b>{@link String}</b> 411 * </p> 412 */ 413 public static final ResourceMetadataKeyEnum<String> VERSION = new ResourceMetadataKeyEnum<String>("VERSION") { 414 private static final long serialVersionUID = 1L; 415 @Override 416 public String get(IResource theResource) { 417 return getStringFromMetadataOrNullIfNone(theResource.getResourceMetadata(), VERSION); 418 } 419 420 @Override 421 public void put(IResource theResource, String theObject) { 422 theResource.getResourceMetadata().put(VERSION, theObject); 423 } 424 }; 425 426 /** 427 * The value for this key is the version ID of the resource object. 428 * <p> 429 * Values for this key are of type <b>{@link IdDt}</b> 430 * </p> 431 * 432 * @deprecated The {@link IResource#getId()} resource ID will now be populated with the version ID via the {@link IdDt#getVersionIdPart()} method 433 */ 434 @Deprecated 435 public static final ResourceMetadataKeyEnum<IdDt> VERSION_ID = new ResourceMetadataKeyEnum<IdDt>("VERSION_ID") { 436 private static final long serialVersionUID = 1L; 437 @Override 438 public IdDt get(IResource theResource) { 439 return getIdFromMetadataOrNullIfNone(theResource.getResourceMetadata(), VERSION_ID); 440 } 441 442 @Override 443 public void put(IResource theResource, IdDt theObject) { 444 theResource.getResourceMetadata().put(VERSION_ID, theObject); 445 } 446 }; 447 448 private final String myValue; 449 450 public ResourceMetadataKeyEnum(String theValue) { 451 myValue = theValue; 452 } 453 454 @Override 455 public boolean equals(Object obj) { 456 if (this == obj) 457 return true; 458 if (obj == null) 459 return false; 460 if (getClass() != obj.getClass()) 461 return false; 462 ResourceMetadataKeyEnum<?> other = (ResourceMetadataKeyEnum<?>) obj; 463 if (myValue == null) { 464 if (other.myValue != null) 465 return false; 466 } else if (!myValue.equals(other.myValue)) 467 return false; 468 return true; 469 } 470 471 public abstract T get(IResource theResource); 472 473 @Override 474 public int hashCode() { 475 final int prime = 31; 476 int result = 1; 477 result = prime * result + ((myValue == null) ? 0 : myValue.hashCode()); 478 return result; 479 } 480 481 public String name() { 482 return myValue; 483 } 484 485 public abstract void put(IResource theResource, T theObject); 486 487 @Override 488 public String toString() { 489 return myValue; 490 } 491 492 private static DecimalDt getDecimalFromMetadataOrNullIfNone(Map<ResourceMetadataKeyEnum<?>, Object> theResourceMetadata, ResourceMetadataKeyEnum<DecimalDt> theKey) { 493 Object retValObj = theResourceMetadata.get(theKey); 494 if (retValObj == null) { 495 return null; 496 } else if (retValObj instanceof DecimalDt) { 497 if (((DecimalDt) retValObj).isEmpty()) { 498 return null; 499 } else { 500 return (DecimalDt) retValObj; 501 } 502 } else if (retValObj instanceof String) { 503 if (StringUtils.isBlank((String) retValObj)) { 504 return null; 505 } 506 return new DecimalDt((String) retValObj); 507 } else if (retValObj instanceof Double) { 508 return new DecimalDt((Double) retValObj); 509 } 510 throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + theKey.name() + " - Expected " 511 + InstantDt.class.getCanonicalName()); 512 } 513 514 @SuppressWarnings("unchecked") 515 private static <T extends Enum<?>> T getEnumFromMetadataOrNullIfNone(Map<ResourceMetadataKeyEnum<?>, Object> theResourceMetadata, ResourceMetadataKeyEnum<T> theKey, Class<T> theEnumType, 516 IValueSetEnumBinder<T> theBinder) { 517 Object retValObj = theResourceMetadata.get(theKey); 518 if (retValObj == null) { 519 return null; 520 } else if (theEnumType.equals(retValObj.getClass())) { 521 return (T) retValObj; 522 } else if (retValObj instanceof String) { 523 return theBinder.fromCodeString((String) retValObj); 524 } 525 throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + theKey.name() + " - Expected " 526 + InstantDt.class.getCanonicalName()); 527 } 528 529 private static IdDt getIdFromMetadataOrNullIfNone(Map<ResourceMetadataKeyEnum<?>, Object> theResourceMetadata, ResourceMetadataKeyEnum<?> theKey) { 530 return toId(theKey, theResourceMetadata.get(theKey)); 531 } 532 533 private static List<IdDt> getIdListFromMetadataOrNullIfNone(Map<ResourceMetadataKeyEnum<?>, Object> theResourceMetadata, ResourceMetadataKeyEnum<?> theKey) { 534 Object retValObj = theResourceMetadata.get(theKey); 535 if (retValObj == null) { 536 return null; 537 } else if (retValObj instanceof List) { 538 List<?> retValList = (List<?>) retValObj; 539 for (Object next : retValList) { 540 if (!(next instanceof IdDt)) { 541 List<IdDt> retVal = new ArrayList<IdDt>(); 542 for (Object nextVal : retValList) { 543 retVal.add(toId(theKey, nextVal)); 544 } 545 return Collections.unmodifiableList(retVal); 546 } 547 } 548 @SuppressWarnings("unchecked") 549 List<IdDt> retVal = (List<IdDt>) retValList; 550 return Collections.unmodifiableList(retVal); 551 } else { 552 return Collections.singletonList(toId(theKey, retValObj)); 553 } 554 } 555 556 private static InstantDt getInstantFromMetadataOrNullIfNone(Map<ResourceMetadataKeyEnum<?>, Object> theResourceMetadata, ResourceMetadataKeyEnum<InstantDt> theKey) { 557 Object retValObj = theResourceMetadata.get(theKey); 558 if (retValObj == null) { 559 return null; 560 } else if (retValObj instanceof Date) { 561 return new InstantDt((Date) retValObj); 562 } else if (retValObj instanceof InstantDt) { 563 if (((InstantDt) retValObj).isEmpty()) { 564 return null; 565 } else { 566 return (InstantDt) retValObj; 567 } 568 } 569 throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + theKey.name() + " - Expected " 570 + InstantDt.class.getCanonicalName()); 571 } 572 573 private static String getStringFromMetadataOrNullIfNone(Map<ResourceMetadataKeyEnum<?>, Object> theResourceMetadata, ResourceMetadataKeyEnum<String> theKey) { 574 Object retValObj = theResourceMetadata.get(theKey); 575 if (retValObj == null) { 576 return null; 577 } else if (retValObj instanceof String) { 578 if (StringUtils.isBlank(((String) retValObj))) { 579 return null; 580 } else { 581 return (String) retValObj; 582 } 583 } 584 throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + theKey.name() + " - Expected " 585 + String.class.getCanonicalName()); 586 } 587 588 private static IdDt toId(ResourceMetadataKeyEnum<?> theKey, Object retValObj) { 589 if (retValObj == null) { 590 return null; 591 } else if (retValObj instanceof String) { 592 if (isNotBlank((String) retValObj)) { 593 return new IdDt((String) retValObj); 594 } else { 595 return null; 596 } 597 } else if (retValObj instanceof IdDt) { 598 if (((IdDt) retValObj).isEmpty()) { 599 return null; 600 } else { 601 return (IdDt) retValObj; 602 } 603 } else if (retValObj instanceof Number) { 604 return new IdDt(((Number) retValObj).toString()); 605 } 606 throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + theKey.name() + " - Expected " 607 + IdDt.class.getCanonicalName()); 608 } 609 610 public static abstract class ResourceMetadataKeySupportingAnyResource<T, T2> extends ResourceMetadataKeyEnum<T> { 611 612 public ResourceMetadataKeySupportingAnyResource(String theValue) { 613 super(theValue); 614 } 615 616 private static final long serialVersionUID = 1L; 617 618 619 public abstract T2 get(IAnyResource theResource); 620 621 public abstract void put(IAnyResource theResource, T2 theObject); 622 623 } 624 625}