001package ca.uhn.fhir.rest.client.interceptor; 002 003/*- 004 * #%L 005 * HAPI FHIR - Client Framework 006 * %% 007 * Copyright (C) 2014 - 2019 University Health Network 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}