001package ca.uhn.fhir.model.api; 002 003/* 004 * #%L 005 * HAPI FHIR - Core Library 006 * %% 007 * Copyright (C) 2014 - 2023 Smile CDR, Inc. 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.i18n.Msg; 024import ca.uhn.fhir.model.base.composite.BaseCodingDt; 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.hl7.fhir.instance.model.api.IAnyResource; 031import org.hl7.fhir.instance.model.api.IBaseResource; 032import org.hl7.fhir.instance.model.api.IPrimitiveType; 033 034import java.io.Serializable; 035import java.util.Date; 036import java.util.List; 037 038/** 039 * 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 040 * data elements which are sent/receieved in HTTP Headers along with read/create resource requests, or properties which can be found in bundle entries. 041 * <p> 042 * 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 043 * {@link #UPDATED} value, which is the "last updated" time for that resource, use the following code: 044 * </p> 045 * <p> 046 * <code>InstantDt updated = ResourceMetadataKeyEnum.UPDATED.get(resource);</code> 047 * <p> 048 * <p> 049 * To set this value, use the following: 050 * </p> 051 * <p> 052 * <code>InstantDt update = new InstantDt("2011-01-02T11:22:33.0000Z"); // populate with the actual time<br> 053 * ResourceMetadataKeyEnum.UPDATED.put(resource, update);</code> 054 * </p> 055 * <p> 056 * 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 057 * define their own keys for storage in resource metadata if needed. 058 * </p> 059 */ 060public abstract class ResourceMetadataKeyEnum<T> implements Serializable { 061 062 /** 063 * 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 064 * of scenarios, such as POSTing transaction bundles to a server, or returning resource history. 065 * <p> 066 * Values for this key are of type <b>{@link InstantDt}</b> 067 * </p> 068 */ 069 public static final ResourceMetadataKeyEnum<IPrimitiveType<Date>> DELETED_AT = new ResourceMetadataKeyEnum<>("DELETED_AT", IPrimitiveType.class) { 070 }; 071 /** 072 * 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. 073 * 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 074 * server, or to "match" to indicate that the resource was returned because it matched the given search criteria. 075 * <p> 076 * Note that status is only used in FHIR DSTU2 and later. 077 * </p> 078 * <p> 079 * Values for this key are of type <b>{@link BundleEntrySearchModeEnum}</b> 080 * </p> 081 */ 082 public static final ResourceMetadataKeyEnum<BundleEntrySearchModeEnum> ENTRY_SEARCH_MODE = new ResourceMetadataKeyEnum<>("ENTRY_SEARCH_MODE", BundleEntrySearchModeEnum.class) { 083 }; 084 /** 085 * 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 086 * 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 087 * 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 088 * result of a transaction to indicate to the client what operation was actually performed. 089 * <p> 090 * Note that status is only used in FHIR DSTU2 and later. 091 * </p> 092 * <p> 093 * Values for this key are of type <b>{@link BundleEntryTransactionMethodEnum}</b> 094 * </p> 095 */ 096 public static final ResourceMetadataKeyEnum<BundleEntryTransactionMethodEnum> ENTRY_TRANSACTION_METHOD = new ResourceMetadataKeyEnum<>("ENTRY_TRANSACTION_OPERATION", BundleEntryTransactionMethodEnum.class) { 097 }; 098 /** 099 * The value for this key represents a {@link List} of profile IDs that this resource claims to conform to. 100 * <p> 101 * <p> 102 * 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. 103 * </p> 104 */ 105 public static final ResourceMetadataKeyEnum<List<IdDt>> PROFILES = new ResourceMetadataKeyEnum<>("PROFILES", List.class) { 106 }; 107 /** 108 * 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. 109 * <p> 110 * Values for this key are of type <b>{@link InstantDt}</b> 111 * </p> 112 * <p> 113 * <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. 114 * </p> 115 * 116 * @see InstantDt 117 */ 118 public static final ResourceMetadataKeyEnum<InstantDt> PUBLISHED = new ResourceMetadataKeyEnum<>("PUBLISHED", InstantDt.class) { 119 }; 120 public static final ResourceMetadataKeyEnum<List<BaseCodingDt>> SECURITY_LABELS = new ResourceMetadataKeyEnum<>("SECURITY_LABELS", List.class) { 121 }; 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 = new ResourceMetadataKeyEnum<>("TAG_LIST", TagList.class) { 131 }; 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 = new ResourceMetadataKeyEnum<>("UPDATED", InstantDt.class) { 142 }; 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 = new ResourceMetadataKeyEnum<>("VERSION", String.class) { 153 }; 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 = new ResourceMetadataKeyEnum<>("VERSION_ID", IdDt.class) { 164 }; 165 private static final long serialVersionUID = 1L; 166 private final String myValue; 167 private final Class<?> myType; 168 169 public ResourceMetadataKeyEnum(String theValue, Class<?> theType) { 170 myValue = theValue; 171 myType = theType; 172 } 173 174 // TODO: JA - Replace all of the various other get/put methods in subclasses with just using the two that are here 175 public T get(IBaseResource theResource) { 176 Object retVal; 177 if (theResource instanceof IAnyResource) { 178 retVal = theResource.getUserData(name()); 179 } else { 180 retVal = ((IResource) theResource).getResourceMetadata().get(this); 181 } 182 183 if (retVal != null && !myType.isAssignableFrom(retVal.getClass())) { 184 throw new InternalErrorException(Msg.code(1890) + "Found an object of type '" + retVal.getClass().getCanonicalName() 185 + "' in resource metadata for key " + this.name() + " - Expected " 186 + myType.getCanonicalName()); 187 } 188 189 //noinspection unchecked 190 return (T) retVal; 191 } 192 193 public void put(IBaseResource theResource, T theValue) { 194 if (theValue != null && !myType.isAssignableFrom(theValue.getClass())) { 195 throw new InternalErrorException(Msg.code(1891) + "Can not put object of type '" + theValue.getClass().getCanonicalName() 196 + "' in resource metadata for key " + this.name() + " - Expected " 197 + myType.getCanonicalName()); 198 } 199 200 if (theResource instanceof IAnyResource) { 201 theResource.setUserData(name(), theValue); 202 } else { 203 ((IResource) theResource).getResourceMetadata().put(this, theValue); 204 } 205 } 206 207 @Override 208 public boolean equals(Object obj) { 209 if (this == obj) 210 return true; 211 if (obj == null) 212 return false; 213 if (getClass() != obj.getClass()) 214 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}