001package ca.uhn.fhir.rest.client.interceptor;
002
003/*-
004 * #%L
005 * HAPI FHIR - Client Framework
006 * %%
007 * Copyright (C) 2014 - 2021 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.rest.client.api.IClientInterceptor;
024import ca.uhn.fhir.rest.client.api.IHttpRequest;
025import ca.uhn.fhir.rest.client.api.IHttpResponse;
026import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
027
028import java.io.IOException;
029
030/**
031 * This is a client interceptor that captures the current request and response
032 * in a ThreadLocal variable, meaning that it can work in multithreaded
033 * environments without mixing up requests.
034 * <p>
035 * Use this with caution, since <b>this interceptor does not automatically clean up</b>
036 * the ThreadLocal after setting it. You must make sure to call
037 * {@link #clearThreadLocals()} after a given request has been completed,
038 * or you will end up leaving stale request/response objects associated
039 * with threads that no longer need them.
040 * </p>
041 *
042 * @see CapturingInterceptor for an equivalent interceptor that does not use a ThreadLocal
043 * @since 3.5.0
044 */
045public class ThreadLocalCapturingInterceptor implements IClientInterceptor {
046
047        private final ThreadLocal<IHttpRequest> myRequestThreadLocal = new ThreadLocal<>();
048        private final ThreadLocal<IHttpResponse> myResponseThreadLocal = new ThreadLocal<>();
049        private boolean myBufferResponse;
050
051        /**
052         * This method should be called at the end of any request process, in
053         * order to clear the last request and response from the current thread.
054         */
055        public void clearThreadLocals() {
056                myRequestThreadLocal.remove();
057                myResponseThreadLocal.remove();
058        }
059
060        public IHttpRequest getRequestForCurrentThread() {
061                return myRequestThreadLocal.get();
062        }
063
064        public IHttpResponse getResponseForCurrentThread() {
065                return myResponseThreadLocal.get();
066        }
067
068        @Override
069        public void interceptRequest(IHttpRequest theRequest) {
070                myRequestThreadLocal.set(theRequest);
071        }
072
073        @Override
074        public void interceptResponse(IHttpResponse theResponse) {
075                if (isBufferResponse()) {
076                        CapturingInterceptor.bufferResponse(theResponse);
077                }
078                myResponseThreadLocal.set(theResponse);
079        }
080
081        /**
082         * Should we buffer (capture) the response body? This defaults to
083         * <code>false</code>. Set to <code>true</code> if you are planning on
084         * examining response bodies after the response processing is complete.
085         */
086        public boolean isBufferResponse() {
087                return myBufferResponse;
088        }
089
090        /**
091         * Should we buffer (capture) the response body? This defaults to
092         * <code>false</code>. Set to <code>true</code> if you are planning on
093         * examining response bodies after the response processing is complete.
094         */
095        public ThreadLocalCapturingInterceptor setBufferResponse(boolean theBufferResponse) {
096                myBufferResponse = theBufferResponse;
097                return this;
098        }
099}