001/*- 002 * #%L 003 * HAPI FHIR - Server Framework 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.rest.api.server; 021 022import ca.uhn.fhir.context.FhirContext; 023import ca.uhn.fhir.context.api.AddProfileTagEnum; 024import ca.uhn.fhir.interceptor.api.HookParams; 025import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster; 026import ca.uhn.fhir.interceptor.api.IInterceptorService; 027import ca.uhn.fhir.interceptor.api.Pointcut; 028import ca.uhn.fhir.interceptor.model.RequestPartitionId; 029import ca.uhn.fhir.rest.api.EncodingEnum; 030import ca.uhn.fhir.rest.server.ETagSupportEnum; 031import ca.uhn.fhir.rest.server.ElementsSupportEnum; 032import ca.uhn.fhir.rest.server.IPagingProvider; 033import ca.uhn.fhir.rest.server.IRestfulServerDefaults; 034import ca.uhn.fhir.rest.server.RestfulServer; 035import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor; 036import com.google.common.collect.ImmutableListMultimap; 037import com.google.common.collect.ListMultimap; 038import com.google.common.collect.MultimapBuilder; 039 040import java.io.IOException; 041import java.io.InputStream; 042import java.io.Reader; 043import java.nio.charset.Charset; 044import java.util.Collections; 045import java.util.List; 046 047import static java.util.Objects.nonNull; 048 049/** 050 * A default RequestDetails implementation that can be used for system calls to 051 * Resource DAO methods when partitioning is enabled. Using a SystemRequestDetails 052 * instance for system calls will ensure that any resource queries or updates will 053 * use the DEFAULT partition when partitioning is enabled. 054 */ 055public class SystemRequestDetails extends RequestDetails { 056 private FhirContext myFhirContext; 057 private ListMultimap<String, String> myHeaders; 058 /** 059 * If a SystemRequestDetails has a RequestPartitionId, it will take precedence over the tenantId 060 */ 061 private RequestPartitionId myRequestPartitionId; 062 063 private IRestfulServerDefaults myServer = new MyRestfulServerDefaults(); 064 065 public SystemRequestDetails() { 066 this(new MyInterceptorBroadcaster()); 067 } 068 069 public SystemRequestDetails(IInterceptorBroadcaster theInterceptorBroadcaster) { 070 super(theInterceptorBroadcaster); 071 } 072 073 public SystemRequestDetails(RequestDetails theDetails) { 074 super(theDetails); 075 if (nonNull(theDetails.getServer())) { 076 myServer = theDetails.getServer(); 077 myFhirContext = theDetails.getFhirContext(); 078 } 079 } 080 081 public RequestPartitionId getRequestPartitionId() { 082 return myRequestPartitionId; 083 } 084 085 public SystemRequestDetails setRequestPartitionId(RequestPartitionId theRequestPartitionId) { 086 myRequestPartitionId = theRequestPartitionId; 087 return this; 088 } 089 090 @Override 091 protected byte[] getByteStreamRequestContents() { 092 return new byte[0]; 093 } 094 095 @Override 096 public Charset getCharset() { 097 return null; 098 } 099 100 @Override 101 public FhirContext getFhirContext() { 102 return myFhirContext; 103 } 104 105 public void setFhirContext(FhirContext theFhirContext) { 106 myFhirContext = theFhirContext; 107 } 108 109 @Override 110 public String getHeader(String name) { 111 List<String> headers = getHeaders(name); 112 if (headers.isEmpty()) { 113 return null; 114 } else { 115 return headers.get(0); 116 } 117 } 118 119 @Override 120 public List<String> getHeaders(String name) { 121 ListMultimap<String, String> headers = myHeaders; 122 if (headers == null) { 123 headers = ImmutableListMultimap.of(); 124 } 125 return headers.get(name); 126 } 127 128 @Override 129 public void addHeader(String theName, String theValue) { 130 initHeaderMap(); 131 myHeaders.put(theName, theValue); 132 } 133 134 @Override 135 public void setHeaders(String theName, List<String> theValues) { 136 initHeaderMap(); 137 myHeaders.putAll(theName, theValues); 138 } 139 140 private void initHeaderMap() { 141 if (myHeaders == null) { 142 // Make sure we are case-insensitive on keys 143 myHeaders = MultimapBuilder.treeKeys(String.CASE_INSENSITIVE_ORDER) 144 .arrayListValues() 145 .build(); 146 } 147 } 148 149 @Override 150 public Object getAttribute(String theAttributeName) { 151 return null; 152 } 153 154 @Override 155 public void setAttribute(String theAttributeName, Object theAttributeValue) {} 156 157 @Override 158 public InputStream getInputStream() throws IOException { 159 return null; 160 } 161 162 @Override 163 public Reader getReader() { 164 return null; 165 } 166 167 @Override 168 public IRestfulServerDefaults getServer() { 169 return myServer; 170 } 171 172 public void setServer(RestfulServer theServer) { 173 this.myServer = theServer; 174 } 175 176 @Override 177 public String getServerBaseForRequest() { 178 return null; 179 } 180 181 private static class MyRestfulServerDefaults implements IRestfulServerDefaults { 182 183 @Override 184 public AddProfileTagEnum getAddProfileTag() { 185 return null; 186 } 187 188 @Override 189 public EncodingEnum getDefaultResponseEncoding() { 190 return null; 191 } 192 193 @Override 194 public ETagSupportEnum getETagSupport() { 195 return null; 196 } 197 198 @Override 199 public ElementsSupportEnum getElementsSupport() { 200 return null; 201 } 202 203 @Override 204 public FhirContext getFhirContext() { 205 return null; 206 } 207 208 @Override 209 public List<IServerInterceptor> getInterceptors_() { 210 return null; 211 } 212 213 @Override 214 public IPagingProvider getPagingProvider() { 215 return null; 216 } 217 218 @Override 219 public boolean isDefaultPrettyPrint() { 220 return false; 221 } 222 223 @Override 224 public IInterceptorService getInterceptorService() { 225 return null; 226 } 227 } 228 229 private static class MyInterceptorBroadcaster implements IInterceptorBroadcaster { 230 231 @Override 232 public boolean callHooks(Pointcut thePointcut, HookParams theParams) { 233 return true; 234 } 235 236 @Override 237 public Object callHooksAndReturnObject(Pointcut thePointcut, HookParams theParams) { 238 return null; 239 } 240 241 @Override 242 public boolean hasHooks(Pointcut thePointcut) { 243 return false; 244 } 245 246 @Override 247 public List<IInvoker> getInvokersForPointcut(Pointcut thePointcut) { 248 return Collections.emptyList(); 249 } 250 } 251 252 public static SystemRequestDetails forAllPartitions() { 253 return new SystemRequestDetails().setRequestPartitionId(RequestPartitionId.allPartitions()); 254 } 255 256 public static SystemRequestDetails newSystemRequestAllPartitions() { 257 SystemRequestDetails systemRequestDetails = new SystemRequestDetails(); 258 systemRequestDetails.setRequestPartitionId(RequestPartitionId.allPartitions()); 259 return systemRequestDetails; 260 } 261}