Announcement Announcement Module
Collapse
No announcement yet.
REST call does not wait for response? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • REST call does not wait for response?

    Hi,

    I want to setup a Spring integration project with a REST call to handle a request existing of some tasks. Tasks must be processed in parallel. However,
    when I use the configuration below, I keep getting following exception:

    Code:
    Exception in thread "main" org.springframework.web.client.RestClientException: Cannot extract response: no Content-Type found
    	at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:66)
    	at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:619)
    	at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:1)
    	at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:446)
    	at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:401)
    	at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:377)
    	at com.mycompany.prototype.CallPrototype.main(CallPrototype.java:48)
    This is because the tasks are still processing, the REST call does not wait for the result. If I remove the task executor on the splitterChannel, everything is processed in sequence and it works, but that's not what I want to achieve. What I am doing wrong here?

    Config:

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xmlns:int="http://www.springframework.org/schema/integration"
    	xmlns:jmx="http://www.springframework.org/schema/integration/jmx"
    	xmlns:int-http="http://www.springframework.org/schema/integration/http"
    	xmlns:task="http://www.springframework.org/schema/task"
    	xmlns:context="http://www.springframework.org/schema/context"
    	xsi:schemaLocation="
    	http://www.springframework.org/schema/beans
    	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    	http://www.springframework.org/schema/integration
    	http://www.springframework.org/schema/integration/spring-integration-2.0.xsd
    	http://www.springframework.org/schema/integration/jmx 
    	http://www.springframework.org/schema/integration/jmx/spring-integration-jmx-2.0.xsd
    	http://www.springframework.org/schema/integration/stream
    	http://www.springframework.org/schema/integration/stream/spring-integration-stream-1.0.xsd
    	http://www.springframework.org/schema/integration/http
    	http://www.springframework.org/schema/integration/http/spring-integration-http-2.0.xsd
    	http://www.springframework.org/schema/task 
    	http://www.springframework.org/schema/task/spring-task-3.0.xsd
    	http://www.springframework.org/schema/context
    	http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    	
    	<context:component-scan base-package="com.mycompany.prototype"/>
    		
    	<int-http:inbound-gateway 
    		request-channel="requestChannel"
    		reply-channel="responseChannel"
            name="/generate.html"                                  
            supported-methods="POST"/> 
    
    	<int:channel id="requestChannel"/>
    	
    	<int:service-activator 
    		input-channel="requestChannel"
    		output-channel="json" 
    		ref="byteHandler"/>
    		
    	<!-- JSON string -->
    	<int:channel id="json" >
    		<int:interceptors>
    			<int:wire-tap channel="logger"/>
    		</int:interceptors>
    	</int:channel>
    		
    	<!--  log channel -->
    	<int:logging-channel-adapter id="logger" level="INFO"/>
    		
    	<int:json-to-object-transformer
    		input-channel="json"
    		output-channel="tasksRequest"
    		type="com.mycompany.prototype.TaskRequest"/>
    		
    	 <!-- Tasks -->
    	<int:channel id="tasksRequest"/>
    	
    	<bean id="pool" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
    		<property name="corePoolSize" value="2"/>
    		<property name="daemon" value="false"/>
    	</bean>
    	
    	<int:splitter 
    		input-channel="tasksRequest"
    		ref="taskSplitter"
    		output-channel="splitterChannel"/>		
    		
    	<int:channel id="splitterChannel">
    		<int:dispatcher task-executor="pool"/>
    	</int:channel>	
    	
    	<!-- route attachments to type processors -->	
    	<int:router input-channel="splitterChannel" ref="taskTypeRouter"/>
    	
    	<int:channel id="tasks1"/>						
    	<int:channel id="tasks2"/>
    						
    	<int:service-activator 
    		input-channel="tasks1" 
    		output-channel="handledTasks" 
    		ref="taskHandler1"/>
    		
    	<int:service-activator 
    		input-channel="tasks2" 
    		output-channel="handledTasks" 
    		ref="taskHandler1"/>
    		
    	<int:channel id="handledTasks"/>	
    	
    	<!--  aggregate -->
    	<int:aggregator 
    		input-channel="handledTasks"
    		output-channel="responseChannel"
    		ref="taskAggregator"/>
    		
        <int:channel id="responseChannel"/>
        	
    </beans>
    call:

    Code:
    RestTemplate template = new RestTemplate();
    		
    		template.getMessageConverters();
    		template.getMessageConverters().add(
    			      new MappingJacksonHttpMessageConverter());
    		
    		HttpEntity<TaskRequest> entity = new HttpEntity<TaskRequest>(req);
    		
    		ResponseEntity<String> response = template.exchange("http://localhost:8080/MailExport/generate.html", HttpMethod.POST, entity, String.class);
    		
    		System.out.println(response);

  • #2
    It seems to me you are not setting a Content-Type header when constructing the request that will be used by the RestTemplate. Please see the following sample which does have RestTemplate=based client http://git.springsource.org/spring-i...multipart-http
    Also, keep in mind that you can issue request via outbound gateway as well. The above sample has such configuration as well.

    Comment


    • #3
      Hi, thank you for the quick response

      I tried to add the content-header, but I got the same result

      Code:
      HttpHeaders headers = new HttpHeaders();
      MediaType jsonMimeType = MediaType.APPLICATION_JSON;
      headers.setContentType(jsonMimeType);
      		
      HttpEntity<TaskRequest> entity = new HttpEntity<TaskRequest>(req, headers);
      IMHO, I think it is not the problem with the REST call, more with the Integration setup, because
      when I change

      Code:
      <int:channel id="splitterChannel">
      	<int:dispatcher task-executor="pool"/>
      </int:channel>
      into

      Code:
            <int:channel id="splitterChannel"/>
      it works, the REST call just waits until the "responseChannel" has returned.

      Comment


      • #4
        Hmm, that doesn't make any sense. All you are doing is changing from DirectChannel to ExecutorChannel. Out of curiosity, what version fo Spring Integration you are using?

        Comment


        • #5
          Strange indeed, I'm using the latest build, 2.0.4

          I've attached my sample code:

          Attachment
          Attached Files

          Comment


          • #6
            Hmm, i can't seem to reproduce it. I'll try a little more, but could you please attach a wiretap and print the Message that goes to the 'responseChannel'. I want to see the full Message.

            Comment


            • #7
              I wiretapped the response channel and got the (expected) result below:

              Code:
              HANDLED: Task 1 - type 1
              HANDLED: Task 2 - type 1
              HANDLED: Task 3 - type 1
              HANDLED: Task 4 - type 2
              To exclude a wrong call, I tried to use RESTclient 2.3.3 and got the same results: when using an ExecutorChannel, I immediately got "HTTP/1.1 200 OK" back, with an empty body (content-length=0). At the same moment, the server is still processing.

              I also tried an updated version of the software: JDK 1.6.0.25, Tomcat 6.0.32, Spring Integration 2.0.4 and Spring Framework 3.0.5

              Still the same results

              Comment


              • #8
                THat is not the output i wanted. I need to see the whole message where i can see what headers are present.

                Comment


                • #9
                  ah, I printed the headers and got following result:

                  Code:
                  {errorChannel=org.springframework.integration.core.MessagingTemplate$TemporaryReplyChannel@1c4e792, replyChannel=org.springframework.integration.core.MessagingTemplate$TemporaryReplyChannel@1c4e792, correlationId=54f97929-b735-4a44-97b6-1bad435a7312, connection=Keep-Alive, http_requestMethod=POST, expect=100-Continue, content-type=application/json;charset=UTF-8, id=ac6526b2-1b3b-42e4-b915-30c937df5029, content-length=243, host=localhost:8080, user-agent=Apache-HttpClient/4.0.1 (java 1.5), timestamp=1306235095863, accept=application/json, http_requestUrl=http://localhost:8080/MailExport/generate.html}
                  I both setups, I get the same headers

                  I used

                  Code:
                  <!--  log channel -->
                  	<int:logging-channel-adapter id="logger" expression="headers" level="INFO"/>

                  Comment


                  • #10
                    Ok, I was able to reproduce it. Let me see what's going on. I'll follow up.

                    Comment


                    • #11
                      Ok, here is what's going on. The reply-timeout on the HttpInboundGateway is set to 1 sec by default. That is how long MessagingTemplate will wait to receive a Message from the reply channel before returning null. Since you have couple of service-activators that take longer than 1 sec to execute (Thread.sleep()), the response can not be produced in 1 sec or less, resulting in no response or should i say response with content-length 0 and obviously no Content-Type set, thus resulting in the client error that you see. Below are all the headers that you see in such response.
                      Code:
                      {Server=[Apache-Coyote/1.1], Content-Length=[0], Date=[Tue, 24 May 2011 14:58:07 GMT]}
                      However, all you need to do to avoid this is to explicitly set the reply-timeout on the Http Inbound Gateway
                      You can set it to some value (e.g., 5000 if you want o wait for the response no longer than 5 sec or -1 if you prepared to wait indefinitely)
                      Here is the config that I use now with your code:
                      Code:
                      <int-http:inbound-gateway 
                      		request-channel="requestChannel"
                      		reply-channel="responseChannel"
                              name="/generate.html"     
                              reply-timeout="-1"                     
                              supported-methods="POST"/>
                      Let me know if you still have issue.

                      Comment


                      • #12
                        Yes! This works!

                        Thanks for the second pair of eyes and the patience

                        Comment

                        Working...
                        X