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}