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