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