INT-1552 doc polishing

This commit is contained in:
Mark Fisher
2010-11-22 13:23:21 -05:00
parent 94e0947289
commit 36e43a8ed1

View File

@@ -21,13 +21,13 @@ public interface Cafe {
]]></programlisting>
Namespace support is also
provided which allows you to configure such interface as a service and is demonstrated by the following example.
provided which allows you to configure such an interface as a service as demonstrated by the following example.
<programlisting language="xml"><![CDATA[<gateway id="cafeService"
service-interface="org.cafeteria.Cafe"
default-request-channel="requestChannel"
default-reply-channel="replyChannel"/>]]></programlisting>
Then, the "cafeService" can be injected into other beans, and the code that invokes the methods on that
With this configuration defined, the "cafeService" can now be injected into other beans, and the code that invokes the methods on that
proxied instance of the Cafe interface has no awareness of the Spring Integration API. The general
approach is similar to that of Spring Remoting (RMI, HttpInvoker, etc.). See the "Samples" Appendix for
an example that uses this "gateway" element (in the Cafe demo).
@@ -42,7 +42,7 @@ public interface Cafe {
void placeOrder(Order order);
}]]></programlisting>
... as well as <code>method</code> sub element if you prefer XML configuration (see next paragraph)
You may alternatively provide such content in <code>method</code> sub-elements if you prefer XML configuration (see the next paragraph).
</para>
<para>
It is also possible to pass values to be interpreted as Message headers on the Message
@@ -56,8 +56,8 @@ public interface Cafe {
</para>
<para>
If you prefer XML way of configuring Gateway methods, you can provide <emphasis>method</emphasis> sub-elements
to the gateway configuration (see below)
If you prefer the XML approach of configuring Gateway methods, you can provide <emphasis>method</emphasis> sub-elements
to the gateway configuration.
<programlisting language="xml"><![CDATA[<si:gateway id="myGateway" service-interface="org.foo.bar.TestGateway"
default-request-channel="inputC">
<si:method name="echo" request-channel="inputA" reply-timeout="2" request-timeout="200"/>
@@ -72,7 +72,7 @@ public interface Cafe {
For example, in the Loan Broker example we want to influence how aggregation of the Loan quotes
will be done based on what type of request was initiated (single quote or all quotes). Determining the
type of the request by evaluating what gateway method was invoked, although possible would
violate the separation of concerns paradigm (method is a java artifact),  but expressing your
violate the separation of concerns paradigm (the method is a java artifact),  but expressing your
intention (meta information) via Message headers is natural in a Messaging architecture.
<programlisting language="xml"><![CDATA[<int:gateway id="loanBrokerGateway"
@@ -84,11 +84,11 @@ public interface Cafe {
<int:header name="RESPONSE_TYPE" value="ALL"/>
</int:method>
</int:gateway>]]></programlisting>
In the above case you can clearly see how a different header value will be set for the 'RESPONSE_TYPE'
In the above case you can clearly see how a different value will be set for the 'RESPONSE_TYPE'
header based on the gateway's method.
</para>
<para>
As with anything else, Gateway invocation might result in errors.
Of course, the Gateway invocation might result in errors.
By default any error that has occurred downstream will be re-thrown as a MessagingException (RuntimeException)
upon the Gateway's method invocation. However there are times when you may want
to simply log the error rather than propagating it, or you may want to treat an
@@ -126,21 +126,24 @@ public interface Cafe {
</para>
<para>
<important>
Exposing messaging system via POJO Gateway is obviously a great benefit, but it does come at the price so there
are certain things you must be aware of.
Exposing the messaging system via simple POJI Gateways obviously provides benefits, but "hiding" the reality
of the underlying messaging system does come at a price so there are certain things you should consider.
We want our Java method to return as quick as possible and not hang for infinite amount of time until they can
return (void , exception or return value). When regular methods are used as a proxies in front of the Messaging
system we have to take into account the asynchronous nature of the Messaging Systems. This means that there might
be a chance that a Message hat was initiated by a Gateway could be dropped by a Filter, thus never reaching a
component that is responsible to produce a reply. Some Service Activator method might result in the Exception,
thus resulting in no-reply (as we don't generate Null messages).So as you can see there are multiple scenarios
where reply message might not be coming which is perfectly natural in messaging systems. However think about the
implication on the gateway method.  The Gateway's method input arguments  were incorporated into a Message and
sent downstream. The reply Message would be converted to a return value of the Gateway's method. So you can see
how ugly it could get if you can not guarantee that for each Gateway call there will alway be a reply Message.
Basically your Gateway method will never return and will hang infinitely.
One of the ways of handling this situation is via AsyncGateway (explained later in this section). Another way of handling it is to explicitly set the reply-timeout attribute. This way gateway will not hang for more then the time that was specified by the reply-timeout and will return 'null'. 
We want our Java method to return as quickly as possible and not hang for an indefinite amount of time while
the caller is waiting on it to return (void, return value, or a thrown Exception). When regular methods are
used as a proxies in front of the Messaging system, we have to take into account the potentially asynchronous
nature of the underlying messaging. This means that there might
be a chance that a Message that was initiated by a Gateway could be dropped by a Filter, thus never reaching a
component that is responsible for producing a reply. Some Service Activator method might result in an Exception,
thus providing no reply (as we don't generate Null messages). So as you can see there are multiple scenarios
where a reply message might not be coming. That is perfectly natural in messaging systems. However think about the
implication on the gateway method. The Gateway's method input arguments  were incorporated into a Message and
sent downstream. The reply Message would be converted to a return value of the Gateway's method. So you might want
to ensure that for each Gateway call there will always be a reply Message.
Otherwise, your Gateway method might never return and will hang indefinitely.
One of the ways of handling this situation is via an Asynchronous Gateway (explained later in this section). Another way of handling it is to explicitly set the reply-timeout attribute. That way, the gateway will not hang any longer than the time specified by the reply-timeout and will return 'null' if that timeout does elapse. Finally, you might want to consider setting downstream flags such as 'requires-reply' on
a service-activator or 'throw-exceptions-on-rejection' on a filter. These options will be discussed in more detail in the final section
of this chapter.
</important>
</para>
</section>
@@ -148,13 +151,13 @@ One of the ways of handling this situation is via AsyncGateway (explained later
<title>Asynchronous Gateway</title>
<para>
As a pattern the Messaging Gateway is a very nice way to hide messaging-specific code while still exposing the full capabilities of the
messaging system. And <classname>GatewayProxyFactoryBean</classname> provides a convenient way to expose a Proxy over a service-interface
thus giving you a POJO-based access to a messaging system (based on objects in your own domain, or primitives/Strings, etc).  But when a
messaging system. As you've seen, the <classname>GatewayProxyFactoryBean</classname> provides a convenient way to expose a Proxy over a service-interface
thus giving you POJO-based access to a messaging system (based on objects in your own domain, or primitives/Strings, etc).  But when a
gateway is exposed via simple POJO methods which return values it does imply that for each Request message (generated when the method is invoked)
there must be a Reply message (generated when the method has returned). Since Messaging systems naturally are asynchronous you may not always be
able to guarantee the contract where <emphasis>"for each request there will always be be a reply"</emphasis>. 
With Spring Integration 2.0 we are introducing support for an <emphasis>Asynchronous Gateway</emphasis> which is a convenient way to initiate
flows where you may not know if a reply is expected or how long will it take for it to arrive.
flows where you may not know if a reply is expected or how long will it take for replies to arrive.
</para>
<para>
A natural way to handle these types of scenarios in Java would be relying upon <emphasis>java.util.concurrent.Future</emphasis> instances, and
@@ -172,12 +175,12 @@ One of the ways of handling this situation is via AsyncGateway (explained later
}</programlisting>
</para>
<para>
As you can see from the example above the return type for the gateway method is <classname>Future</classname>. When
As you can see from the example above the return type for the gateway method is a <classname>Future</classname>. When
<classname>GatewayProxyFactoryBean</classname> sees that the
return type of the gateway method is <classname>Future</classname>, it immediately switches to the async mode by utilizing
an <classname>AsyncTaskExecutor</classname>. That is all. The call to a method always returns immediately with <classname>Future</classname>
encapsulating  the interaction with the framework.
Now you can interact with the <classname>Future</classname> at your own pace to get the result, timeout, get the exception etc...
return type of the gateway method is a <classname>Future</classname>, it immediately switches to the async mode by utilizing
an <classname>AsyncTaskExecutor</classname>. That is all. The call to such a method always returns immediately with a <classname>Future</classname> instance.
Then, you can interact with the <classname>Future</classname> at your own pace to get the result, cancel, etc. And, as with
any other use of Future instances, calling get() may reveal a timeout, an execution exception, and so on.
<programlisting language="java">MathServiceGateway mathService = ac.getBean("mathService", MathServiceGateway.class);
Future&lt;Integer&gt; result = mathService.multiplyByTwo(number);
// do something else here since the reply might take a moment
@@ -187,13 +190,13 @@ For a more detailed example, please refer to the <emphasis>async-gateway</emphas
</section>
<section>
<title>Gateway behavior when no response is coming</title>
<title>Gateway behavior when no response arrives</title>
<para>
As it was explained earlier, Gateway provides a convenient way of interacting with Messaging system via POJO method
invocations, but realizing that a typical method invocation, which is generally expected to always return (even with Exception),
might not always map one-to-one to message exchanges (e.g., reply message might not be coming which is equivalent to
method not returning), it is important to go over several scenarios especially in the Sync Gateway case and understand
what the default behavior of the Gateway and how to deal with these scenarios to make Sync Gateway behavior more
As it was explained earlier, the Gateway provides a convenient way of interacting with a Messaging system via POJO method
invocations, but realizing that a typical method invocation, which is generally expected to always return (even with an Exception),
might not always map one-to-one to message exchanges (e.g., a reply message might not arrive - which is equivalent to a
method not returning). It is important to go over several scenarios especially in the Sync Gateway case and understand
the default behavior of the Gateway and how to deal with these scenarios to make the Sync Gateway behavior more
predictable regardless of the outcome of the message flow that was initialed from such Gateway.
</para>
<para>
@@ -209,16 +212,15 @@ For a more detailed example, please refer to the <emphasis>async-gateway</emphas
</para>
<para>
<emphasis>Sync Gateway - single-threaded</emphasis>.
If a component downstream is still running (e.g., infinite loop or a very slow service), then setting <emphasis>reply-timeout</emphasis>
has no effect and Gateway method call will not return until such downstream service exits (e.g., return or exception).
If a component downstream is still running (e.g., infinite loop or a very slow service), then setting a <emphasis>reply-timeout</emphasis>
has no effect and the Gateway method call will not return until such downstream service exits (via return or exception).
<emphasis>Sync Gateway - multi-threaded</emphasis>.
If a component downstream is still running (e.g., infinite loop or a very slow service), in a multi-threaded message
flow setting <emphasis>reply-timeout</emphasis> will have an effect by allowing gateway method invocation to
return once the timeout has been reached, since <classname>GatewayProxyFactoryBean</classname>  will simply
poll on the reply channel waiting for a message until the timeout expires. However it could result in the 'null' return
flow setting the <emphasis>reply-timeout</emphasis> will have an effect by allowing gateway method invocation to
return once the timeout has been reached, since the <classname>GatewayProxyFactoryBean</classname>  will simply
poll on the reply channel waiting for a message until the timeout expires. However it could result in a 'null' return
from the Gateway method if the timeout has been reached before the actual reply was produced. It is also important to understand that
the reply message (if produced) will be sent to a reply channel after Gateway method invocation might have returned, so you must be aware of that
and design your flow with this in mind.
the reply message (if produced) will be sent to a reply channel after the Gateway method invocation might have returned, so you must be aware of that and design your flow with this in mind.
</para>
<para>
<emphasis>Downstream component returns 'null'</emphasis>
@@ -226,9 +228,9 @@ For a more detailed example, please refer to the <emphasis>async-gateway</emphas
<para>
<emphasis>Sync Gateway - single-threaded</emphasis>.
If a component downstream returns 'null' and no <emphasis>reply-timeout</emphasis> has been configured, the Gateway
method call will hang indefinitely unless: a) <emphasis>reply-timeout</emphasis> has been configured or b)
method call will hang indefinitely unless: a) a <emphasis>reply-timeout</emphasis> has been configured or b) the
<emphasis>requires-reply</emphasis> attribute has been set on the downstream component (e.g., service-activator)
that might return 'null'. In this case, the exception will be thrown and propagated to the Gateway.
that might return 'null'. In this case, an Exception would be thrown and propagated to the Gateway.
<emphasis>Sync Gateway - multi-threaded</emphasis>. Behavior is the same as above.
</para>
<para>
@@ -237,7 +239,7 @@ For a more detailed example, please refer to the <emphasis>async-gateway</emphas
<para>
<emphasis>Sync Gateway - single-threaded</emphasis>.
If a component downstream returns 'void' and no <emphasis>reply-timeout</emphasis> has been configured,
the Gateway method call will hang indefinitely unless <emphasis>reply-timeout</emphasis> has been configured 
the Gateway method call will hang indefinitely unless a <emphasis>reply-timeout</emphasis> has been configured 
<emphasis>Sync Gateway - multi-threaded</emphasis> Behavior is the same as above.
</para>
<para>
@@ -245,7 +247,7 @@ For a more detailed example, please refer to the <emphasis>async-gateway</emphas
</para>
<para>
<emphasis>Sync Gateway - single-threaded</emphasis>.
If a component downstream throws a Runtime Exception, such exception will be propagated via Error Message back to
If a component downstream throws a Runtime Exception, such exception will be propagated via an Error Message back to
the gateway and re-thrown.
<emphasis>Sync Gateway - multi-threaded</emphasis> Behavior is the same as above.
</para>
@@ -253,18 +255,21 @@ For a more detailed example, please refer to the <emphasis>async-gateway</emphas
<important>
It is also important to understand that by default <emphasis>reply-timeout</emphasis> is unbounded which means that
if not explicitly set there are several scenarios (described above) where your Gateway method invocation might
hang indefinitely, so make sure you analyze your flow and if there is even a remote possibility of one of these
scenarios to occur, set the <emphasis>reply-timeout</emphasis> attribute to a 'safe' value or better off
set the <emphasis>requires-reply</emphasis> attribute of the downstream component to 'true' to ensure a timely response.
hang indefinitely. So, make sure you analyze your flow and if there is even a remote possibility of one of these
scenarios to occur, set the <emphasis>reply-timeout</emphasis> attribute to a 'safe' value or, even better,
set the <emphasis>requires-reply</emphasis> attribute of the downstream component to 'true' to ensure a timely response
as produced by the throwing of an Exception as soon as that downstream component does return null internally.
But also, realize that there are some scenarios (see the very first one)
where <emphasis>reply-timeout</emphasis> will not help which means it is also important to analyze your message
flow and decide when to use Sync Gateway vs Async Gateway where Gateway method invocation is always guaranteed
to return while giving you a more granular control over the results of the invocation via Java Futures.
where <emphasis>reply-timeout</emphasis> will not help. That means it is also important to analyze your message
flow and decide when to use a Sync Gateway vs an Async Gateway. As you've seen the latter case is simply a matter of
defining Gateway methods that return Future instances. Then, you are guaranteed to receive that return value, and
you will have more granular control over the results of the invocation.
<para>
Also, when dealing with Router you should remember that setting <emphasis>resolution-required</emphasis> attribute to 'true'
will result in the exception thrown by the router if it can not resolve a particular channel. And when dealing with the filter
you can also set <emphasis>throw-exception-on-rejection</emphasis> attribute. Both of these will help to ensure a timely response
from the Gateway method invocation.
Also, when dealing with a Router you should remember that setting the <emphasis>resolution-required</emphasis> attribute to 'true'
will result in an Exception thrown by the router if it can not resolve a particular channel. Likewise, when dealing with a Filter,
you can set the <emphasis>throw-exception-on-rejection</emphasis> attribute. In both of these cases, the resulting flow will
behave like that containing a service-activator with the 'requires-reply' attribute. In other words, it will help to ensure
a timely response from the Gateway method invocation.
</para>
</important>
</para>