Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RmiOutboundGateway does not correctly check if the original outgoing message had an "errorChannel" header [INT-3031] #7005

Closed
spring-operator opened this issue May 23, 2013 · 11 comments
Assignees
Milestone

Comments

@spring-operator
Copy link
Contributor

Jürgen Failenschmid opened INT-3031 and commented

If an exception is propagated from RmiInboundGateway to RmiOutboundGateway, the exception is always sent to the special channel "errorChannel". RmiOutboundGateway does not correctly check if the original outgoing message had an "errorChannel" header.

The exception propagates just fine, but RmiOutboundGateway's exception handling always ignores the header "errorChannel" of the outgoing message. Instead, all exceptions are routed to the special "errorChannel". I think the intention of the code is (or should be) to first check the "errorChannel" header, and only if the header is missing, route to the default error channel.

For example, it should be sufficient to configure this pair of RMI gateways in the two JVMs and a server-side exception should be routed to the channel specified in the outgoing message's "errorChannel" header.

Client:

<si-rmi:outbound-gateway 
        request-channel="xmlRequestChannel" reply-channel="rmiReplyChannel"
        remote-channel="rmiInboundChannel" 
        host="${java.rmi.server.hostname:localhost}" port="${rmi.registry.port:0}"
        <si:poller fixed-delay="100" receive-timeout="60000" />
</si-rmi:outbound-gateway>

Server:

<si-rmi:inbound-gateway id="rmiInboundGateway" request-channel="rmiInboundChannel" registry-port="${rmi.registry.port:0}" />

Affects: 2.2.3

Reference URL: http://forum.springsource.org/showthread.php?137806-RMI-gateway-error-channel-issues

Attachments:

@spring-operator
Copy link
Contributor Author

Gary Russell commented

The errorChannel header is not used in that way. Exceptions are always propagated to the inbound endpoint of a particular flow (whatever started the flow on the client side in your case). In most cases, this is the default errorChannel, but can be configured on the inbound endpoint (or poller).

The errorChannel header is an internal device used by the framework to get an error response back to the originating gateway if the message has been handed off to another thread.

@spring-operator
Copy link
Contributor Author

Jürgen Failenschmid commented

I discovered this issue for an inbound web-service gateway. Regular replies and downstream exceptions were arriving correctly at the WS gateway and translated into SOAP responses.

As soon as I introduced the RmiOutboundGateway into the message flow, regular reply messages were still going to the WS gateway. However, any exceptions coming from the remote server were ending up in the default "errorChannel", instead of going back to the WS gateway.

I verified that the outbound messages arriving at the RmiOutboundGateway had the correct headers for "replyChannel" and "errorChannel". RmiOutboundGateway should not ignore the "errorChannel" header.

@spring-operator
Copy link
Contributor Author

Gary Russell commented

That's not what I would expect; the ErrorMessage should not end up in the default errorChannel.

The exception propagated from the remote server should be propagated to the inbound gateway, the same as any other. Can you share your full config on the client side, and perhaps a DEBUG log that exhibits this behavior?

@spring-operator
Copy link
Contributor Author

Gary Russell commented

I just ran a test and all works as I would have expected.

I posted a Gist here... https://gist.github.com/garyrussell/5639657 that illustrates the behavior when the upstream inbound gateway has an error channel, and when it does not.

@spring-operator
Copy link
Contributor Author

Jürgen Failenschmid commented

Client beans configuration and debug-level log for a request that resulted in an exception propagated from the RMI server.

@spring-operator
Copy link
Contributor Author

Jürgen Failenschmid commented

I removed too much from the client beans configuration.

This bean is the inbound web-service gateway:

<si-ws:inbound-gateway id="wsInboundEndpoint" 
    request-channel="requestChannel" reply-timeout="60000"
    marshaller="wsMarshaller" unmarshaller="wsMarshaller"/>

@spring-operator
Copy link
Contributor Author

Gary Russell commented

Aha!

The missing piece of the puzzle is you have a queue channel in the flow; my test case worked because I was using a direct channel.

Because RMI exchanges messages with the remote system, when the remote system throws an exception, the exception that the outbound gateway receives contains a failedMessage which is actually the failed message at the point it fails on the remote system, not the message that arrived at the gateway. Since the errorChannel in that message lives on the remote system, it is stripped before the exception is returned to the sender. The gateway re-throws the remote exception (containing the failedMessage with no headers).

When the exception is thrown back to the poller, it's MessagePublishingErrorHandler can't find the header so it sends it to the default errorChannel.

Thanks for finding this and sorry it took so long to figure out what happened; I failed to notice the <poller/> in your gateway config in the forum post; if you'd have included the channel, it would have been more obvious to me.

I need to discuss the fix for this with Mark Fisher.

For all other outbound gateways, the failedMessage in the exception is the message that arrived at the gateway.

So we have a few choices - make the failedMessage consistent with this and just use the message that arrived at the gateway (and drop or log the remote failedMessage) or, leave the failedMessage as the one that failed on the remote machine, but restore the headers or, wrap the entire remote MessagingException with a new local MessagingException so that...

e.failedMessage is the local failed message (at the gateway) and e.cause.failedMessage is the remote failed message.

@spring-operator
Copy link
Contributor Author

Gary Russell commented

FWIW, the fix for the third option is as simple as...

diff --git a/spring-integration-rmi/src/main/java/org/springframework/integration/rmi/RmiOutboundGateway.java b/spring-integration-rmi/src/main/java/org/springframework/int
index c6c4eaf..181af82 100644
--- a/spring-integration-rmi/src/main/java/org/springframework/integration/rmi/RmiOutboundGateway.java
+++ b/spring-integration-rmi/src/main/java/org/springframework/integration/rmi/RmiOutboundGateway.java
...
@@ -62,6 +63,9 @@ public class RmiOutboundGateway extends AbstractReplyProducingMessageHandler {
                        }
                        return reply;
                }
+               catch (MessagingException e) {
+                       throw new MessageHandlingException(message, e);
+               }
                catch (RemoteAccessException e) {
                        throw new MessageHandlingException(message, "remote failure in RmiOutboundGateway", e);
                }

@spring-operator
Copy link
Contributor Author

Jürgen Failenschmid commented

No problem, Gary. You have been very helpful. Thank you!

@spring-operator
Copy link
Contributor Author

Gary Russell commented

#818

cherry-pick to 2.2.x

@spring-operator
Copy link
Contributor Author

Mark Fisher commented

Merged the PR and cherry-picked to 2.2.x branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants