spring-projects / spring-integration

Spring Integration provides an extension of the Spring programming model to support the well-known Enterprise Integration Patterns (EIP)
http://projects.spring.io/spring-integration/
Apache License 2.0
1.54k stars 1.1k forks source link

Http Gateway needs HttpResponseHandler in HttpRequestMessageHandler [INT-1587] #5540

Closed spring-operator closed 13 years ago

spring-operator commented 13 years ago

sridhar kondoji opened INT-1587 and commented

I believe that HttpGateway should give more power to hanlde responses for variety of use cases. This is more importatnt for configurations that requires a reply. Also for those configurations, where you don't expect a response, you may still have a need to handle http response and or tracking purposes.

In my case, i am pumping in thousands of leads pulling messages from Websphere Service integration Bus via jms endpoint (MDCA) and then pass it to our customers via http gateway. We have a use case to track http response for every request, store the response in database along with few request parameters and after x retries for failed deliveries send the request to a different destination on websphere.

We do most of the above said requirements after getting the response from http gateway onto a outputchannel. We also install error handler for restTemplate to not throw any exceptions and simply return as we will be handling the exceptions downstream after http gateway.

I have made a copy of HttpRequestMessageHandler and added responseHandler property to it. This is my interface and its implementation.

public interface IHttpResponseHandler { public Object handleResponse (Message\<?> requestMsg, ResponseEntity\<?> httpResponse); }

My implementation of this interface is simple. Add relevant details of request message or prepare a response message from request message and return the result as object.This implementation will give me an opportunity to send the request message to a different destination after x retries.

The default implementation of responseHandler will be whatever that is there in handleRequestMessage(..) in preparing response. This will also help to wire-tap in the downstream for auditing or for send the response message back to analytics consumption. Hope this is clear.


Affects: 2.0 M1, 2.0 M2, 2.0 M3, 2.0 M4, 2.0 M5, 2.0 M6, 2.0 M7, 2.0 RC1

Reference URL: http://forum.springsource.org/showthread.php?t=97499

Issue Links:

spring-operator commented 13 years ago

Oleg Zhurakousky commented

Aligning it with 2.0.1 so it doesn't get lost

spring-operator commented 13 years ago

Mark Fisher commented

The extension points that we expose are HttpMessageConverter and HeaderMapper.

Can you explain why those are not sufficient for your use-case?

spring-operator commented 13 years ago

sridhar kondoji commented

HeaderMapper allows to pull headers from response entity. I need to pull headers from RequestMessage and add it to ResponseMessage.

On HttpMessageConverter, i thought this can be used only to convert request message from one format to the other? I didn't know, that you can apply this converter to build a ResponseMessage by picking information from RequesMessage. Can you show me sample to achieve this? Thanks sri

spring-operator commented 13 years ago

Mark Fisher commented

Headers from the request message should already be present in the response message that is sent to the output-channel unless they have been overridden. Have you verified that they aren't in fact available?

spring-operator commented 13 years ago

sridhar kondoji commented

I think this is what is happening. The existing implementation makes the following call builder.copyHeadersIfAbsent(requestHeaders);
Rather than builder.copyHeaders(requestHeaders); You can add a property to the namespace declaration to make the appropriate call and partially fix this to address my usecase.

However, the other usecase iam unable to get it working is to send the request message to a different Queue on my JMS provider after x retries. This is because, i don't have a handle of the thread that is executing this whole thing and also access to request message after performing http post.

Now that 2.0 has added new functionality which i haven't explored yet, i have to see if i can get access to request message after http post and do the needful. Thanks sri

spring-operator commented 13 years ago

Mark Fisher commented

Why do you need builder.copyHeaders(requestHeaders); instead of builder.copyHeadersIfAbsent(requestHeaders); ?

The reason we use the latter is that any headers in the response Message should take precedence over those in the request Message. Can you explain why you want to ignore some response Message headers? There might be another way to handle it.

spring-operator commented 13 years ago

Mark Fisher commented

I'm moving this to 2.0.2 until we can clarify the use-case a bit.

spring-operator commented 13 years ago

sridhar kondoji commented

My Response Type is 'String' and for some reason, EntityResponse headers is null for me. this.headerMapper.toHeaders(httpResponse.getHeaders(); So, there is no carry over of headers from EntityResponse in my case. Don't know why?

The reason why i want request message headers to take precendence is because of one header property 'JMSXDeliveryCount' This count is always 1 for response message but can be 1 or greater than 1 for Request message depending on the retry.

Mark: I agree that from your point of view, Response message hearders takes precendence, but for my usecase either one of the following should be provided a) Give me an option to overwrite Response message headers. Or b) Access to RequestMessage copy after the performing Http Post.

Thanks Sri

spring-operator commented 13 years ago

Mark Fisher commented

It sounds to me like you should probably copy that header value into a different header by using a header-enricher prior to the HTTP request/reply adapter. For example, you could have something like this:

<header-enricher input-channel="in" output-channel="out">
    <header name="requestJMSXDeliveryCount" expression="headers.JMSXDeliveryCount"/>
</header-enricher>

That is "safer" since response Message headers take precedence over headers with the same name.

Another potential option would be to provide your own HeaderMapper that ignores the JMSXDeliveryCount header from the response message.

Would either approach work for you?

spring-operator commented 13 years ago

sridhar kondoji commented

Hi Mark, Thank you for your response. After going through your suggestions, almost all my needs are covered except one. How do i get a http response message with both http status code and response text? Preferably status code in header and http response text in body of message. Currently we are going to production on Jan 3. There will be one more rewrite of this code to add two more outbound endpoints for 2 of our customers who are interested in our real time leads. I will take your suggestions and work on it.

While looking at the code, it appeared that even using a HttpMessageConverter to return an Spring integration message with statuscode and response text is not possible as read method gets HttpInputMessage and not ClientHttpResponse where the status code value and response text are available.

Thanks again sri

spring-operator commented 13 years ago

Mark Fisher commented

Can you open a new issue for adding the response's status-code to a header in the case that a response body is returned?

Would you expect it to be stored in the header as an Integer value or an instance of our HttpStatus enum?

If you open that issue, can we also close this current one?

Thanks, Mark

spring-operator commented 13 years ago

sridhar kondoji commented

Issue opened: https://jira.springsource.org/browse/INT-1679 Yes, you can close the current issue.

Integer status code is preferable for us in the Message header. Thanks again for all your help. -sri

spring-operator commented 13 years ago

Mark Fisher commented

Okay. Sounds good. I will resolve this issue as being superseded by #5675.

spring-operator commented 13 years ago

Mark Fisher commented

I'm thinking about this some more... when we return a response Message for those HTTP Responses that have no body, we store the HttpStatus enum instance in the payload. For consistency, I would prefer to put that same enum instance in the header to address this issue (rather than the Integer). Since the int code is available (also as a String from the toString() method), as well as other info like the "Series" (might be useful for routing, e.g. 'status.series == 5' indicates "server error"), it would be more flexible to have that enum instance. Also, it would work well with any SpEL expressions being used downstream.

Would you mind if we store the enum instance instead of Integer?

spring-operator commented 13 years ago

sridhar kondoji commented

no problem. It works for me too. Go ahead and add enum and i can get the value iam looking for. Thanks sri

spring-operator commented 13 years ago

Mark Fisher commented

Changing this resolution to "Won't Fix" since the use-case is now handled via the existing behavior and the addition of the status code header as described in #5675.