title: Spring Integration: inbound-gateway management is slower by 20 seconds instead of @Controller management
body: <p>I have two Spring MVC applications; I'm using Spring Integration HTTP to integrate them.</p>
  
  <p><strong>The process</strong></p>
  
  <p>The process is very simple: an HTTP GET request directed to the <em>"application1"</em> is managed by a <code>@Controller</code> and then "transfered" to the <em>"application2"</em> with an <code>&lt;int-http:outbound-gateway&gt;</code> through an HTTP POST.</p>
  
  <p>Once there, this POST (intermediate) request is managed and transfered to another URI of the <em>"application2"</em> (with another <code>&lt;int-http:outbound-gateway&gt;</code>), <strong>that provides the real response</strong>.</p>
  
  <p><strong>The issue</strong></p>
  
  <p>I have noticed a different behaviour in the request management on the <em>"application2"</em> side (which is invoked by the <code>&lt;int-http:outbound-gateway&gt;</code> of the <em>"application1"</em>).</p>
  
  <p>If I use a <code>@Controller</code> to manage the "intermediate" URI, the process execution needs some milliseconds to be accomplished.</p>
  
  <p>But if I use an <code>&lt;int-http:inbound-gateway&gt;</code> to replicate the same process, <strong>it needs 20 seconds to complete the process</strong>: why this difference?</p>
  
  <p>This is the implementation with the <code>@Controller</code>:</p>
  
  <pre><code>@Controller
  @RequestMapping(value="/service")
  public class ServiceController {
  
      @RequestMapping(value="/{resource}", method=RequestMethod.POST)
      public void resource(@PathVariable(value="resource") String resource, HttpServletRequest request, HttpServletResponse res){
          handleRequest(resource,request, res);
      }
  
      private void handleRequest(String resource, HttpServletRequest request, HttpServletResponse res) throws Exception {
          // READING THE REQUEST PAYLOAD
          RequestHandler requestHandler = RequestHandler.getHandler(request);         
          RequestPayload payload = requestHandler.getPayload();
  
          // PREPARING THE MESSAGE TO THE CHANNEL
          MessagingChannel messagingChannel = (MessagingChannel)ApplicationContextResolver.getApplicationContext().getBean("requestChannelBean");
          MessageChannel requestChannel = messagingChannel.getRequestChannel();
          MessagingTemplate messagingTemplate = new MessagingTemplate();
          String url = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+request.getServletContext().getContextPath()+request.getServletPath()+"/"+resource;
          Message&lt;?&gt; requestMessage = MessageBuilder.withPayload(url).build();
  
          // SEND THE MESSAGE AND RECEIVE THE RESPONSE
          Message&lt;?&gt; response = messagingTemplate.sendAndReceive(requestChannel, requestMessage);
  
          // PRINT THE RESPONSE
          res.getWriter().write((String)response.getPayload());
  
      }
  }
  </code></pre>
  
  <p>This solution works perfectly and it needs a few milliseconds to return the response.</p>
  
  <p>The following is the implementation with the <code>&lt;int-http:inbound-gateway&gt;</code> and the <code>&lt;int:service-activator&gt;</code> that I'm trying to use to <strong>replicate</strong> the <code>@Controller</code> solution:</p>
  
  <pre><code>&lt;int:service-activator id="channelServiceActivator"
      ref="channelService"
      input-channel="requestChannel"      
      method="manage"/&gt;
  
  &lt;int-http:inbound-gateway id="gateway" request-channel="requestChannel"
                path="/service/**" 
                supported-methods="POST"
                header-mapper="headerMapper"&gt;
      &lt;int-http:header name="requestAttributes" expression="#requestAttributes"/&gt;
  &lt;/int-http:inbound-gateway&gt;
  </code></pre>
  
  <p>With this service activator:</p>
  
  <pre><code>public class ChannelService {
  
      public String manage(Message&lt;?&gt; message) throws Throwable{
  
          // RECOVERING THE HttpServletRequest
          ServletRequestAttributes sra = (ServletRequestAttributes) message.getHeaders().get("requestAttributes");
          HttpServletRequest request = sra.getRequest();
  
          // RETRIEVING THE PAYLOAD
          Object payload = message.getPayload();
  
          // PREPARING THE MESSAGE TO THE CHANNEL
          MessagingChannel messagingChannel = (MessagingChannel)ApplicationContextResolver.getApplicationContext().getBean("requestChannelBean");
          MessageChannel requestChannel = messagingChannel.getRequestChannel();
          MessagingTemplate messagingTemplate = new MessagingTemplate();
          String url = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+request.getServletContext().getContextPath()+request.getServletPath()+"/"+resource;
          Message&lt;?&gt; requestMessage = MessageBuilder.withPayload(url).build();
  
          // SEND THE MESSAGE AND RECEIVE THE RESPONSE
          Message&lt;?&gt; response = messagingTemplate.sendAndReceive(requestChannel, requestMessage);
  
          // RETURN THE RESPONSE
          return (String) response.getPayload(); // &lt;- since here, the behaviour is normal. 
                                                 // The framework needs 20 seconds after this instruction
  
      }
  }   
  </code></pre>
  
  <p><strong>This implementation needs 20 seconds to be completed for every request</strong>, I don't understand the reason for that.
  I don't see any error in the Spring logs, I only see that the system seems to "freeze": it not logs anything anymore for 20 seconds.</p>
  
  <p>Any explanation would be appreciated.</p>
  
  <p><strong>UPDATE</strong></p>
  
  <p>Here the logs.
  After the "HttpMessageConverterExtractor.extractData:101", it needs 20 seconds before seing the others "org.springframework.integration.http" logs (2016-07-29 15:06:18 -> 2016-07-29 15:06:38).</p>
  
  <pre><code>2016-07-29 15:06:18 TRACE [] org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.close:217 (http-nio-8080-exec-4) - Logical connection closed
  GenericMessage [payload={
    "_embedded" : {
      "persons" : [ ]
    },
    "_links" : {
      "self" : {
        "href" : "http://localhost:8080/application2/api/persons"
      },
      "profile" : {
        "href" : "http://localhost:8080/application2/api/profile/persons"
      },
      "search" : {
        "href" : "http://localhost:8080/application2/api/persons/search"
      }
    }
  }, headers={Transfer-Encoding=chunked, Server=Apache-Coyote/1.1, Accept=application/json, X-Content-Type-Options=nosniff, Pragma=no-cache, http_statusCode=200, Date=1469797578000, X-Frame-Options=DENY, Cache-Control=no-cache, no-store, max-age=0, must-revalidate, id=2b6b0b80-82bc-2ce7-c364-1e84c389bc71, X-XSS-Protection=1; mode=block, contentType=application/json, timestamp=1469797578411}]
  2016-07-29 15:06:18 DEBUG [] org.springframework.web.client.RestTemplate.handleResponse:658 (executor-1) - POST request for "http://localhost:8080/application2/api/service/persons" resulted in 200 (OK)
  2016-07-29 15:06:18 DEBUG [] org.springframework.web.client.HttpMessageConverterExtractor.extractData:101 (executor-1) - Reading [java.lang.String] as "application/octet-stream" using [org.springframework.http.converter.StringHttpMessageConverter@5397e277]
  2016-07-29 15:06:38 DEBUG [] org.springframework.integration.http.support.DefaultHttpHeaderMapper.toHeaders:436 (executor-1) - inboundHeaderNames=[*]
  2016-07-29 15:06:38 DEBUG [] org.springframework.integration.http.support.DefaultHttpHeaderMapper.shouldMapHeader:537 (executor-1) - headerName=[server] WILL be mapped, matched pattern=*
  2016-07-29 15:06:38 DEBUG [] org.springframework.integration.http.support.DefaultHttpHeaderMapper.toHeaders:463 (executor-1) - setting headerName=[Server], value=[Apache-Coyote/1.1]
  2016-07-29 15:06:38 DEBUG [] org.springframework.integration.http.support.DefaultHttpHeaderMapper.shouldMapHeader:537 (executor-1) - headerName=[pragma] WILL be mapped, matched pattern=*
  2016-07-29 15:06:38 DEBUG [] org.springframework.integration.http.support.DefaultHttpHeaderMapper.toHeaders:463 (executor-1) - setting headerName=[Pragma], value=no-cache
  2016-07-29 15:06:38 DEBUG [] org.springframework.integration.http.support.DefaultHttpHeaderMapper.shouldMapHeader:537 (executor-1) - headerName=[accept] WILL be mapped, matched pattern=*
  2016-07-29 15:06:38 DEBUG [] org.springframework.integration.http.support.DefaultHttpHeaderMapper.toHeaders:463 (executor-1) - setting headerName=[Accept], value=[application/json]
  2016-07-29 15:06:38 DEBUG [] org.springframework.integration.http.support.DefaultHttpHeaderMapper.shouldMapHeader:537 (executor-1) - headerName=[host] WILL be mapped, matched pattern=*
  2016-07-29 15:06:38 DEBUG [] org.springframework.integration.http.support.DefaultHttpHeaderMapper.toHeaders:463 (executor-1) - setting headerName=[host], value=[localhost:8080]
  2016-07-29 15:06:38 DEBUG [] org.springframework.integration.http.support.DefaultHttpHeaderMapper.shouldMapHeader:537 (executor-1) - headerName=[connection] WILL be mapped, matched pattern=*
  2016-07-29 15:06:38 DEBUG [] org.springframework.integration.http.support.DefaultHttpHeaderMapper.toHeaders:463 (executor-1) - setting headerName=[connection], value=[keep-alive]
  2016-07-29 15:06:38 DEBUG [] org.springframework.integration.http.support.DefaultHttpHeaderMapper.shouldMapHeader:537 (executor-1) - headerName=[cache-control] WILL be mapped, matched pattern=*
  2016-07-29 15:06:38 DEBUG [] org.springframework.integration.http.support.DefaultHttpHeaderMapper.toHeaders:463 (executor-1) - setting headerName=[Cache-Control], value=no-cache
  2016-07-29 15:06:38 DEBUG [] org.springframework.integration.http.support.DefaultHttpHeaderMapper.shouldMapHeader:537 (executor-1) - headerName=[user-agent] WILL be mapped, matched pattern=*
  2016-07-29 15:06:38 DEBUG [] org.springframework.integration.http.support.DefaultHttpHeaderMapper.toHeaders:463 (executor-1) - setting headerName=[user-agent], value=[Java/1.8.0_65]
  2016-07-29 15:06:38 DEBUG [] org.springframework.integration.http.support.DefaultHttpHeaderMapper.shouldMapHeader:537 (executor-1) - headerName=[x-xss-protection] WILL be mapped, matched pattern=*
  2016-07-29 15:06:38 DEBUG [] org.springframework.integration.http.support.DefaultHttpHeaderMapper.toHeaders:454 (executor-1) - setting headerName=[X-XSS-Protection], value=[1; mode=block]
  2016-07-29 15:06:38 DEBUG [] org.springframework.integration.http.support.DefaultHttpHeaderMapper.shouldMapHeader:537 (executor-1) - headerName=[x-frame-options] WILL be mapped, matched pattern=*
  2016-07-29 15:06:38 DEBUG [] org.springframework.integration.http.support.DefaultHttpHeaderMapper.toHeaders:454 (executor-1) - setting headerName=[X-Frame-Options], value=[DENY]
  2016-07-29 15:06:38 DEBUG [] org.springframework.integration.http.support.DefaultHttpHeaderMapper.shouldMapHeader:537 (executor-1) - headerName=[x-content-type-options] WILL be mapped, matched pattern=*
  2016-07-29 15:06:38 DEBUG [] org.springframework.integration.http.support.DefaultHttpHeaderMapper.toHeaders:454 (executor-1) - setting headerName=[X-Content-Type-Options], value=[nosniff]
  2016-07-29 15:06:38 DEBUG [] org.springframework.integration.http.support.DefaultHttpHeaderMapper.shouldMapHeader:537 (executor-1) - headerName=[content-type] WILL be mapped, matched pattern=*
  2016-07-29 15:06:38 DEBUG [] org.springframework.integration.http.support.DefaultHttpHeaderMapper.toHeaders:463 (executor-1) - setting headerName=[Content-Type], value=application/octet-stream
  2016-07-29 15:06:38 DEBUG [] org.springframework.integration.http.support.DefaultHttpHeaderMapper.shouldMapHeader:537 (executor-1) - headerName=[content-length] WILL be mapped, matched pattern=*
  2016-07-29 15:06:38 DEBUG [] org.springframework.integration.http.support.DefaultHttpHeaderMapper.toHeaders:463 (executor-1) - setting headerName=[Content-Length], value=968
  2016-07-29 15:06:38 DEBUG [] org.springframework.integration.http.support.DefaultHttpHeaderMapper.shouldMapHeader:537 (executor-1) - headerName=[date] WILL be mapped, matched pattern=*
  2016-07-29 15:06:38 DEBUG [] org.springframework.integration.http.support.DefaultHttpHeaderMapper.toHeaders:463 (executor-1) - setting headerName=[Date], value=1.469.797.578.000
  answer: {
    "_embedded" : {
      "persons" : [ ]
    },
    "_links" : {
      "self" : {
        "href" : "http://localhost:8080/application2/api/persons"
      },
      "profile" : {
        "href" : "http://localhost:8080/application2/api/profile/persons"
      },
      "search" : {
        "href" : "http://localhost:8080/application2/api/persons/search"
      }
    }
  }
  2016-07-29 15:06:38 TRACE [] org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest:138 (http-nio-8080-exec-2) - Method [sendMessageToChannel] returned [null]
  2016-07-29 15:06:38 DEBUG [] org.springframework.web.servlet.DispatcherServlet.processDispatchResult:1044 (http-nio-8080-exec-2) - Null ModelAndView returned to DispatcherServlet with name 'dispatcher': assuming HandlerAdapter completed request handling
  2016-07-29 15:06:38 TRACE [] org.springframework.web.servlet.FrameworkServlet.resetContextHolders:1062 (http-nio-8080-exec-2) - Cleared thread-bound request context: SecurityContextHolderAwareRequestWrapper[ org.springframework.security.web.context.HttpSessionSecurityContextRepository$Servlet3SaveToSessionRequestWrapper@9bacc4f]
  2016-07-29 15:06:38 DEBUG [] org.springframework.web.servlet.FrameworkServlet.processRequest:1000 (http-nio-8080-exec-2) - Successfully completed request
  2016-07-29 15:06:38 TRACE [] org.springframework.context.support.AbstractApplicationContext.publishEvent:362 (http-nio-8080-exec-2) - Publishing event in WebApplicationContext for namespace 'dispatcher-servlet': ServletRequestHandledEvent: url=[/application1/api/persons/]; client=[0:0:0:0:0:0:0:1]; method=[GET]; servlet=[dispatcher]; session=[null]; user=[null]; time=[21426ms]; status=[OK]
  2016-07-29 15:06:38 TRACE [] org.springframework.context.support.AbstractApplicationContext.publishEvent:362 (http-nio-8080-exec-2) - Publishing event in Root WebApplicationContext: ServletRequestHandledEvent: url=[/application1/api/persons/]; client=[0:0:0:0:0:0:0:1]; method=[GET]; servlet=[dispatcher]; session=[null]; user=[null]; time=[21426ms]; status=[OK]
  2016-07-29 15:06:38 DEBUG [] org.springframework.security.web.access.ExceptionTranslationFilter.doFilter:117 (http-nio-8080-exec-2) - Chain processed normally
  2016-07-29 15:06:38 DEBUG [] org.springframework.security.web.header.writers.HstsHeaderWriter.writeHeaders:130 (http-nio-8080-exec-2) - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@7ffcc692
  2016-07-29 15:06:38 DEBUG [] org.springframework.security.web.context.HttpSessionSecurityContextRepository$SaveToSessionResponseWrapper.saveContext:352 (http-nio-8080-exec-2) - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
  2016-07-29 15:06:38 DEBUG [] org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter:119 (http-nio-8080-exec-2) - SecurityContextHolder now cleared, as request processing completed
  </code></pre>
  
  <p><strong>UPDATE 2</strong></p>
  
  <p>I have investigated more the process:</p>
  
  <ul>
  <li>The <code>outbound-gateway</code> (application1) sends a message to a remote endpoint (application2) with the "<code>sendAndReceive()</code>"; the message contains the header "<code>application/octet-stream</code>", because I pass a Byte Array as payload.</li>
  <li>The remote endpoint (application2) has an <code>inbound-gateway</code> with a service activator</li>
  <li>The <code>service activator</code> (application2) processes the request and returns a String.</li>
  <li>The <code>HttpMessageConverterExtractor</code> (application1) try to read the response with the <em>contentType</em> of the message that has been sent to the "application2" (<code>application/octet-stream</code>).</li>
  </ul>
  
  <p>I think that the problem is right here: I have sent a message with the <code>outbound-gateway</code> with the header <code>application/octet-stream</code>, <strong>but in response I have to receive a String</strong> (with <code>application/json</code>), <strong>not an application/octet-stream</strong>.</p>
  
  <p>These are the informations of the <code>inputMessage</code> variable used by the <code>readInternal</code> method of the class <code>org.springframework.http.converter.StringHttpMessageConverter</code>:</p>
  
  <pre><code>inputMessage    MessageBodyClientHttpResponseWrapper  (id=111)  
      pushbackInputStream PushbackInputStream  (id=146)   
      response    SimpleClientHttpResponse  (id=121)  
          connection  HttpURLConnection  (id=125) 
          headers HttpHeaders  (id=182)   {Server=[Apache-Coyote/1.1], Pragma=[no-cache], Accept=[application/json], host=[localhost:8080], connection=[keep-alive], Cache-Control=[no-cache], user-agent=[Java/1.8.0_65], X-XSS-Protection=[1; mode=block], X-Frame-Options=[DENY], X-Content-Type-Options=[nosniff], Content-Type=[application/octet-stream], Content-Length=[968], Date=[Mon, 01 Aug 2016 12:52:47 GMT]}
          responseStream  HttpURLConnection$HttpInputStream  (id=180) 
  </code></pre>
  
  <p>The <em>Content-Type</em> is <code>application/octet-stream</code>, but <strong>this must to be refered only to the message in outbound</strong>, not for the inbound message obtained in answer!</p>
  
  <p>There is any way to configure the content type of the response that can receive an outbound-gateway?</p>
  
  <p>My Service activator of application2 process the answer in this way:</p>
  
  <pre><code>public class ChannelService {
  
      public String manage(Message&lt;?&gt; message) throws Throwable{          
          ServletRequestAttributes sra = (ServletRequestAttributes) message.getHeaders().get("requestAttributes");
          HttpServletRequest request = sra.getRequest();
          System.out.println(request.getRequestURL());
  
          Object payload = message.getPayload();
  
          return "{ \"test\" : \"test\"}";
      }
  
  }
  </code></pre>
  
  <p><strong>UPDATE 3</strong></p>
  
  <p>The problem is the <code>InputStream</code> obtained by the <code>HttpInputMessage</code> with <code>inputMessage.getBody()</code>.</p>
  
  <p>While this InputStream is processed with the "<code>read()</code>" method, the result of the "<code>read()</code>" is never -1 for 20 seconds.
  I have implemented a custom <code>StringHttpMessageConverter</code>:</p>
  
  <pre><code>@Override
  protected String readInternal(Class&lt;? extends String&gt; clazz, HttpInputMessage inputMessage)
          throws IOException, HttpMessageNotReadableException {
      System.out.println("ResponseStringHttpMessageConverter.readInternal()");
  
      int content;
      long start = System.currentTimeMillis();
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      while ( ( content = inputMessage.getBody().read()) != -1){
          System.out.println(content);
          baos.write(content);
      }   
      long end = System.currentTimeMillis();
      System.out.println("TIME READING: "+(end-start));
      String response = baos.toString();
      System.out.println(response);
      return response;
  }
  </code></pre>
  
  <p>The custom <code>readInternal</code> method prints every single character ASCII code, after the last character it stops printing and when it restarts it prints:</p>
  
  <pre><code>TIME READING: 20164
  </code></pre>
  
  <p>So I suppose that there is something wrong in the InputStream of the message, because the read() method doesn't return "-1" before 20 seconds.</p>
  
  <p><strong>UPDATE 4</strong></p>
  
  <p>I solved the problem in the Converter side, but there is the same problem in the closing of the response in the <code>doExecute()</code> method of the <code>org.springframework.web.client.RestTemplate</code> class.</p>
  
  <p>The method try to close the response (an instance of <code>org.springframework.http.client.SimpleClientHttpResponse</code>):</p>
  
  <pre><code>@Override
  public void close() {
      if (this.responseStream != null) {
          try {
              StreamUtils.drain(this.responseStream); // &lt;- again the same problem
              this.responseStream.close();
          }
          catch (IOException e) { }
      }
  }
  </code></pre>
  
  <p>This is the <code>"drain"</code> implementation of <code>org.springframework.util.StreamUtils</code> class:</p>
  
  <pre><code>public static int drain(InputStream in) throws IOException {
      Assert.notNull(in, "No InputStream specified");
      byte[] buffer = new byte[BUFFER_SIZE];
      int bytesRead = -1;
      int byteCount = 0;
      while ((bytesRead = in.read(buffer)) != -1) { // it blocks here !!!
          byteCount += bytesRead;
      }
      return byteCount;
  }
  </code></pre>
  
  <p>In my converter I solved the problem using a buffer with the expected available buffer size:</p>
  
  <pre><code>byte[] buffer = new byte[in.available()];
  in.read(buffer);
  baos.write(buffer); // (a simple ByteArrayOutputStream)
  </code></pre>
  
  <p>I definitely convinced that there is something wrong in my configuration of the outbound-gateway / inbound-gateway / service activator, because the response cause a block just before reading the -1 byte of EOS.
  Otherwise there would be a bug, and I don't believe in this option.</p>