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