001/* 002 * #%L 003 * HAPI FHIR - Core Library 004 * %% 005 * Copyright (C) 2014 - 2024 Smile CDR, Inc. 006 * %% 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 * #L% 019 */ 020package ca.uhn.fhir.model.api; 021 022import ca.uhn.fhir.i18n.Msg; 023import ca.uhn.fhir.model.base.composite.BaseCodingDt; 024import ca.uhn.fhir.model.primitive.IdDt; 025import ca.uhn.fhir.model.primitive.InstantDt; 026import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum; 027import ca.uhn.fhir.model.valueset.BundleEntryTransactionMethodEnum; 028import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; 029import org.hl7.fhir.instance.model.api.IAnyResource; 030import org.hl7.fhir.instance.model.api.IBaseResource; 031import org.hl7.fhir.instance.model.api.IPrimitiveType; 032 033import java.io.Serializable; 034import java.util.Date; 035import java.util.List; 036 037/** 038 * 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 039 * data elements which are sent/receieved in HTTP Headers along with read/create resource requests, or properties which can be found in bundle entries. 040 * <p> 041 * 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 042 * {@link #UPDATED} value, which is the "last updated" time for that resource, use the following code: 043 * </p> 044 * <p> 045 * <code>InstantDt updated = ResourceMetadataKeyEnum.UPDATED.get(resource);</code> 046 * <p> 047 * <p> 048 * To set this value, use the following: 049 * </p> 050 * <p> 051 * <code>InstantDt update = new InstantDt("2011-01-02T11:22:33.0000Z"); // populate with the actual time<br> 052 * ResourceMetadataKeyEnum.UPDATED.put(resource, update);</code> 053 * </p> 054 * <p> 055 * 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 056 * define their own keys for storage in resource metadata if needed. 057 * </p> 058 */ 059public abstract class ResourceMetadataKeyEnum<T> implements Serializable { 060 061 /** 062 * 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 063 * of scenarios, such as POSTing transaction bundles to a server, or returning resource history. 064 * <p> 065 * Values for this key are of type <b>{@link InstantDt}</b> 066 * </p> 067 */ 068 public static final ResourceMetadataKeyEnum<IPrimitiveType<Date>> DELETED_AT = 069 new ResourceMetadataKeyEnum<>("DELETED_AT", IPrimitiveType.class) {}; 070 /** 071 * 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. 072 * 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 073 * server, or to "match" to indicate that the resource was returned because it matched the given search criteria. 074 * <p> 075 * Note that status is only used in FHIR DSTU2 and later. 076 * </p> 077 * <p> 078 * Values for this key are of type <b>{@link BundleEntrySearchModeEnum}</b> 079 * </p> 080 */ 081 public static final ResourceMetadataKeyEnum<BundleEntrySearchModeEnum> ENTRY_SEARCH_MODE = 082 new ResourceMetadataKeyEnum<>("ENTRY_SEARCH_MODE", BundleEntrySearchModeEnum.class) {}; 083 /** 084 * 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 085 * 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 086 * 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 087 * result of a transaction to indicate to the client what operation was actually performed. 088 * <p> 089 * Note that status is only used in FHIR DSTU2 and later. 090 * </p> 091 * <p> 092 * Values for this key are of type <b>{@link BundleEntryTransactionMethodEnum}</b> 093 * </p> 094 */ 095 public static final ResourceMetadataKeyEnum<BundleEntryTransactionMethodEnum> ENTRY_TRANSACTION_METHOD = 096 new ResourceMetadataKeyEnum<>("ENTRY_TRANSACTION_OPERATION", BundleEntryTransactionMethodEnum.class) {}; 097 /** 098 * The value for this key represents a {@link List} of profile IDs that this resource claims to conform to. 099 * <p> 100 * <p> 101 * 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. 102 * </p> 103 */ 104 public static final ResourceMetadataKeyEnum<List<IdDt>> PROFILES = 105 new ResourceMetadataKeyEnum<>("PROFILES", List.class) {}; 106 /** 107 * 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. 108 * <p> 109 * Values for this key are of type <b>{@link InstantDt}</b> 110 * </p> 111 * <p> 112 * <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. 113 * </p> 114 * 115 * @see InstantDt 116 */ 117 public static final ResourceMetadataKeyEnum<InstantDt> PUBLISHED = 118 new ResourceMetadataKeyEnum<>("PUBLISHED", InstantDt.class) {}; 119 120 public static final ResourceMetadataKeyEnum<List<BaseCodingDt>> SECURITY_LABELS = 121 new ResourceMetadataKeyEnum<>("SECURITY_LABELS", List.class) {}; 122 /** 123 * The value for this key is the list of tags associated with this resource 124 * <p> 125 * Values for this key are of type <b>{@link TagList}</b> 126 * </p> 127 * 128 * @see TagList 129 */ 130 public static final ResourceMetadataKeyEnum<TagList> TAG_LIST = 131 new ResourceMetadataKeyEnum<>("TAG_LIST", TagList.class) {}; 132 /** 133 * 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 134 * case of methods that return a single resource (read, vread, etc.) 135 * <p> 136 * Values for this key are of type <b>{@link InstantDt}</b> 137 * </p> 138 * 139 * @see InstantDt 140 */ 141 public static final ResourceMetadataKeyEnum<InstantDt> UPDATED = 142 new ResourceMetadataKeyEnum<>("UPDATED", InstantDt.class) {}; 143 /** 144 * The value for this key is the version ID of the resource object. 145 * <p> 146 * Values for this key are of type <b>{@link String}</b> 147 * </p> 148 * 149 * @deprecated The {@link IResource#getId()} resource ID will now be populated with the version ID via the {@link IdDt#getVersionIdPart()} method 150 */ 151 @Deprecated 152 public static final ResourceMetadataKeyEnum<String> VERSION = 153 new ResourceMetadataKeyEnum<>("VERSION", String.class) {}; 154 /** 155 * The value for this key is the version ID of the resource object. 156 * <p> 157 * Values for this key are of type <b>{@link IdDt}</b> 158 * </p> 159 * 160 * @deprecated The {@link IResource#getId()} resource ID will now be populated with the version ID via the {@link IdDt#getVersionIdPart()} method 161 */ 162 @Deprecated 163 public static final ResourceMetadataKeyEnum<IdDt> VERSION_ID = 164 new ResourceMetadataKeyEnum<>("VERSION_ID", IdDt.class) {}; 165 166 private static final long serialVersionUID = 1L; 167 private final String myValue; 168 private final Class<?> myType; 169 170 public ResourceMetadataKeyEnum(String theValue, Class<?> theType) { 171 myValue = theValue; 172 myType = theType; 173 } 174 175 // TODO: JA - Replace all of the various other get/put methods in subclasses with just using the two that are here 176 public T get(IBaseResource theResource) { 177 Object retVal; 178 if (theResource instanceof IAnyResource) { 179 retVal = theResource.getUserData(name()); 180 } else { 181 retVal = ((IResource) theResource).getResourceMetadata().get(this); 182 } 183 184 if (retVal != null && !myType.isAssignableFrom(retVal.getClass())) { 185 throw new InternalErrorException(Msg.code(1890) + "Found an object of type '" 186 + retVal.getClass().getCanonicalName() 187 + "' in resource metadata for key " + this.name() + " - Expected " 188 + myType.getCanonicalName()); 189 } 190 191 //noinspection unchecked 192 return (T) retVal; 193 } 194 195 public void put(IBaseResource theResource, T theValue) { 196 if (theValue != null && !myType.isAssignableFrom(theValue.getClass())) { 197 throw new InternalErrorException(Msg.code(1891) + "Can not put object of type '" 198 + theValue.getClass().getCanonicalName() 199 + "' in resource metadata for key " + this.name() + " - Expected " 200 + myType.getCanonicalName()); 201 } 202 203 if (theResource instanceof IAnyResource) { 204 theResource.setUserData(name(), theValue); 205 } else { 206 ((IResource) theResource).getResourceMetadata().put(this, theValue); 207 } 208 } 209 210 @Override 211 public boolean equals(Object obj) { 212 if (this == obj) return true; 213 if (obj == null) return false; 214 if (getClass() != obj.getClass()) return false; 215 ResourceMetadataKeyEnum<?> other = (ResourceMetadataKeyEnum<?>) obj; 216 if (myValue == null) { 217 return other.myValue == null; 218 } else return myValue.equals(other.myValue); 219 } 220 221 @Override 222 public int hashCode() { 223 final int prime = 31; 224 int result = 1; 225 result = prime * result + ((myValue == null) ? 0 : myValue.hashCode()); 226 return result; 227 } 228 229 public String name() { 230 return myValue; 231 } 232 233 public static final class ExtensionResourceMetadataKey extends ResourceMetadataKeyEnum<ExtensionDt> { 234 public ExtensionResourceMetadataKey(String theUrl) { 235 super(theUrl, ExtensionDt.class); 236 } 237 } 238}