INT-1552 doc polishing, and added @ManagedResource/@ManagedOperation on the AbstractMessageRouter (for dynamic control over mappings)
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
A <classname>PayloadTypeRouter</classname> will send Messages to the channel as defined by payload-type
|
||||
mappings.
|
||||
<programlisting language="xml"><![CDATA[<bean id="payloadTypeRouter" class="org.springframework.integration.router.PayloadTypeRouter">
|
||||
<property name="payloadTypeChannelMap">
|
||||
<property name="channelIdentifierMap">
|
||||
<map>
|
||||
<entry key="java.lang.String" value-ref="stringChannel"/>
|
||||
<entry key="java.lang.Integer" value-ref="integerChannel"/>
|
||||
@@ -26,10 +26,11 @@
|
||||
</bean>]]></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
Configuration of <classname>PayloadTypeRouter</classname> is also supported via the namespace provided by Spring Integration (see <xref linkend="configuration-namespace"/>),
|
||||
which essentially simplifies configuration by combining <code><router/></code> configuration and its corresponding implementation defined using <code><bean/></code> element
|
||||
Configuration of the <classname>PayloadTypeRouter</classname> is also supported via the namespace provided by Spring Integration (see <xref linkend="configuration-namespace"/>),
|
||||
which essentially simplifies configuration by combining the <code><router/></code> configuration and its corresponding implementation
|
||||
defined using a <code><bean/></code> element
|
||||
into a single and more concise configuration element.
|
||||
The example below demonstrates a <classname>PayloadTypeRouter</classname> configuration which is equivalent to the one above using Spring Integration's namespace support:
|
||||
The example below demonstrates a <classname>PayloadTypeRouter</classname> configuration which is equivalent to the one above using the namespace support:
|
||||
</para>
|
||||
<para>
|
||||
<programlisting language="xml"><![CDATA[<payload-type-router input-channel="routingChannel">
|
||||
@@ -42,7 +43,7 @@
|
||||
<title>HeaderValueRouter</title>
|
||||
<para>
|
||||
A <classname>HeaderValueRouter</classname> will send Messages to the channel based on the individual header value mappings.
|
||||
When <code>HeaderValueRouter</code> is created it is initialized with the <emphasis>name</emphasis> of the header to be evaluated.
|
||||
When a <code>HeaderValueRouter</code> is created it is initialized with the <emphasis>name</emphasis> of the header to be evaluated.
|
||||
The <emphasis>value</emphasis> of the header could be one of two things:</para>
|
||||
<para>
|
||||
1. Arbitrary value
|
||||
@@ -51,11 +52,11 @@
|
||||
2. Channel name
|
||||
</para>
|
||||
<para>
|
||||
If arbitrary then additional mapping of these header values to channel names is required, otherwise no additional configuration is needed.
|
||||
If arbitrary then additional mappings for these header values to channel names is required, otherwise no additional configuration is needed.
|
||||
</para>
|
||||
<para>
|
||||
Spring Integration provides a simple namespace-based XML configuration to configure <classname>HeaderValueRouter</classname>.
|
||||
The example below demonstrates two types of namespace-based configuration of <classname>HeaderValueRouter</classname>.
|
||||
Spring Integration provides a simple namespace-based XML configuration to configure a <classname>HeaderValueRouter</classname>.
|
||||
The example below demonstrates two types of namespace-based configuration for the <classname>HeaderValueRouter</classname>.
|
||||
</para>
|
||||
<para><emphasis>1. Configuration where mapping of header values to channels is required</emphasis> </para>
|
||||
<para>
|
||||
@@ -69,7 +70,8 @@
|
||||
exception. If you want to suppress such exceptions and send unresolved messages to the default output channel
|
||||
(identified with the <code>default-output-channel</code> attribute) set <code>ignore-channel-name-resolution-failures</code> to true.
|
||||
Normally, messages for which the header value is not explicitly mapped to a channel will be sent to the <code>default-output-channel</code>.
|
||||
However, in cases where the header value is mapped to a channel name but the channel cannot be resolved, setting <code>ignore-channel-name-resolution-failures</code>
|
||||
However, in cases where the header value is mapped to a channel name but the channel cannot be resolved, setting
|
||||
the <code>ignore-channel-name-resolution-failures</code>
|
||||
attribute to true will result in routing such messages to the <code>default-output-channel</code>.
|
||||
</para>
|
||||
|
||||
@@ -106,7 +108,7 @@
|
||||
</para>
|
||||
</section>
|
||||
<para>
|
||||
Spring Integration also provides namespace support for <classname>RecipientListRouter</classname> configuration (see <xref linkend="configuration-namespace"/>)
|
||||
Spring Integration also provides namespace support for the <classname>RecipientListRouter</classname> configuration (see <xref linkend="configuration-namespace"/>)
|
||||
as the example below demonstrates.
|
||||
</para>
|
||||
<para>
|
||||
@@ -120,12 +122,14 @@
|
||||
</para>
|
||||
<note>
|
||||
The 'apply-sequence' flag here has the same effect as it does for a publish-subscribe-channel,
|
||||
and like publish-subscribe-channel, it is disabled by default on the recipient-list-router. Refer to
|
||||
and like a publish-subscribe-channel, it is disabled by default on the recipient-list-router. Refer to
|
||||
<xref linkend="channel-configuration-pubsubchannel"/> for more information.
|
||||
</note>
|
||||
|
||||
<para>
|
||||
Another convenient option to configure <classname>RecipientListRouter</classname> is to use Spring Expression Language (SpEL) support
|
||||
Another convenient option when configuring a <classname>RecipientListRouter</classname> is to use Spring Expression Language (SpEL) support
|
||||
as selectors for individual recipient channels. This is similar to using a Filter at the beginning of 'chain' to act as a "Selective Consumer".
|
||||
However, in this case, it's all combined rather concisely into the router's configuration.
|
||||
|
||||
<programlisting language="xml"><![CDATA[<int:recipient-list-router id="customRouter" input-channel="routingChannel">
|
||||
<int:recipient channel="channel1" selector-expression="payload.equals('foo')"/>
|
||||
@@ -142,7 +146,7 @@
|
||||
<section id="router-namespace">
|
||||
<title>Configuring Router</title>
|
||||
<section>
|
||||
<title>Configuring Router with XML</title>
|
||||
<title>Configuring a Content Based Router with XML</title>
|
||||
<para>
|
||||
The "router" element provides a simple way to connect a router to an input channel and also accepts the
|
||||
optional <code>default-output-channel</code> attribute. The <code>ref</code> attribute references the bean name of a custom Router implementation
|
||||
@@ -173,17 +177,17 @@
|
||||
</para>
|
||||
</note>
|
||||
<para>
|
||||
<emphasis>Routers and Spring Expression Language (SpEL)</emphasis>
|
||||
<emphasis>Routers and the Spring Expression Language (SpEL)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
Sometimes the routing logic may be simple and writing a separate class for it and configuring it as a bean may seem
|
||||
like overkill. Since Spring Integration 2.0 we offer an alternative where you can now use
|
||||
like overkill. As of Spring Integration 2.0 we offer an alternative where you can now use
|
||||
<ulink url="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/expressions.htm">SpEL</ulink>
|
||||
to implement simple computations that previously required a custom POJO router.
|
||||
|
||||
<programlisting language="xml"><![CDATA[<int:router input-channel="inChannel" expression="payload + 'Channel'"/>]]></programlisting>
|
||||
In the above configuration the result channel will be computed by the SpEL expression which simply concatenates the value
|
||||
of the <code>payload</code> with the literal 'Channel'
|
||||
of the <code>payload</code> with the literal String 'Channel'.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@@ -203,7 +207,7 @@
|
||||
</section>
|
||||
|
||||
<section id="router-annotation">
|
||||
<title>Configuring Router with Annotations</title>
|
||||
<title>Configuring a Router with Annotations</title>
|
||||
<para>
|
||||
When using <interfacename>@Router</interfacename> to annotate a method, the method may return either a
|
||||
<interfacename>MessageChannel</interfacename> or <classname>String</classname> type. In the latter case,
|
||||
@@ -363,7 +367,7 @@ public List<String> route(@Header("orderStatus") OrderStatus status)</prog
|
||||
However if we look at the alternate configuration of the <classname>HeaderValueRouter</classname> we clearly see that
|
||||
there is no <code>mapping</code> sub element:
|
||||
<programlisting language="xml"><![CDATA[<header-value-router input-channel="inputChannel" header-name="testHeader">]]></programlisting>
|
||||
But the configuration is still perfectly valid. So the natural question is what about the maping in the Step 2?
|
||||
But the configuration is still perfectly valid. So the natural question is what about the mapping in the Step 2?
|
||||
</para>
|
||||
<para>
|
||||
What this means is that Step 2 is now an optional step. If mapping is not defined then the <code>channel identifier</code>
|
||||
@@ -376,53 +380,54 @@ public List<String> route(@Header("orderStatus") OrderStatus status)</prog
|
||||
</para>
|
||||
<para><emphasis>For Example:</emphasis> </para>
|
||||
<para>
|
||||
In the above configuration lets assume that the <code>testHeader</code> value is 'kermit' which is now a <code>channel identifier</code>
|
||||
In the above configuration let's assume that the <code>testHeader</code> value is 'kermit' which is now a <code>channel identifier</code>
|
||||
(Step 1). Since there is no mapping in this router, resolving this <code>channel identifier</code> to a <code>channel name</code>
|
||||
(Step 2) is impossible and this <code>channel identifier</code> is now treated as <code>channel name</code>. However what if
|
||||
there was a mapping but for a different value, the end result would still be the same and that is:
|
||||
<emphasis>if new value can not be determined through the process of resolving 'channel identifier' to a 'channel name',
|
||||
such 'channel identifier' becomes 'channel name'</emphasis>
|
||||
there was a mapping but for a different value? The end result would still be the same and that is:
|
||||
<emphasis>if new value cannot be determined through the process of resolving the 'channel identifier' to a 'channel name',
|
||||
such 'channel identifier' becomes 'channel name'.</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
So all that is left is for Step 3 to resolve <code>channel name</code> ('kermit') to an actual instance of the
|
||||
<classname>MessageChannel</classname> identified by this name. That will be done via a default
|
||||
<interface>ChannelResolver</interface> implementation which is a <classname>BeanFactoryChannelResolver</classname> which
|
||||
basically does a bean lookup by the name provided. So now all messages which contain the header/value pair as <code>testHeader=kermit</code>
|
||||
are going to be routed to a 'kermit' <classname>MessageChannel</classname>.
|
||||
So all that is left is for Step 3 to resolve the <code>channel name</code> ('kermit') to an actual instance of the
|
||||
<classname>MessageChannel</classname> identified by this name. That will be done via the default
|
||||
<interface>ChannelResolver</interface> implementation which is a <classname>BeanFactoryChannelResolver</classname>. It
|
||||
basically does a bean lookup for the name provided. So now all messages which contain the header/value pair as <code>testHeader=kermit</code>
|
||||
are going to be routed to a <classname>MessageChannel</classname> whose bean name (id) is 'kermit'.
|
||||
</para>
|
||||
<para>
|
||||
But what if you want to route these messages to 'simpson' channel? Obviously changing a static configuration will work,
|
||||
But what if you want to route these messages to the 'simpson' channel? Obviously changing a static configuration will work,
|
||||
but will also require bringing your system down. However if you had access to the <code>channel identifier</code> map, then you
|
||||
could just introduce a new mapping where header/value pair is now <code>kermit=simpson</code>, thus allowing Step 2 to treat
|
||||
'kermit' as <code>channel identifier</code> while resolving it to 'simpson' as <code>channel name</code> .
|
||||
could just introduce a new mapping where the header/value pair is now <code>kermit=simpson</code>, thus allowing Step 2 to treat
|
||||
'kermit' as a <code>channel identifier</code> while resolving it to 'simpson' as the <code>channel name</code> .
|
||||
</para>
|
||||
<para>
|
||||
The same obviously applies for <classname>PayloadTypeRouter</classname> where you can now remap or remove a particular <emphasis>payload type
|
||||
mapping</emphasis>, and every other router including <emphasis>expression-based</emphasis> routers since their computed value
|
||||
will now have a chance to go through Step 2 to be aditionally resolved to the actual <code>channel name</code>.
|
||||
mapping</emphasis>. In fact, it applies to every other router including <emphasis>expression-based</emphasis> routers since their computed values
|
||||
will now have a chance to go through Step 2 to be additionally resolved to the actual <code>channel name</code>.
|
||||
</para>
|
||||
<para>
|
||||
In Spring Integration 2.0 the routers hierarchy underwent major refactoring and now any router that is a subclass of the
|
||||
In Spring Integration 2.0 the routers hierarchy underwent significant refactoring so that now any router that is a subclass of the
|
||||
<classname>AbstractMessageRouter</classname> (which includes all framework defined routers) is a Dynamic Router simply because the
|
||||
<code>channelIdentiferMap</code> is defined at the <classname>AbstractMessageRouter</classname> with convenient accessors
|
||||
and modifiers exposed as public methods allowing you to change/add/remove router mapping at runtime via JMX (see <xref linkend="jmx"/>) or
|
||||
the ControlBus (see <xref linkend="control-bus"/>) functionality.
|
||||
<code>channelIdentiferMap</code> is defined at the <classname>AbstractMessageRouter</classname> level. That map's setter method is
|
||||
exposed as a public method along with 'setChannelMapping' and 'removeChannelMapping' methods. These allow you to change/add/remove
|
||||
router mappings at runtime as long as you have a reference to the router itself. It also means that you could expose these same
|
||||
configuration options via JMX (see <xref linkend="jmx"/>) or the Spring Integration ControlBus (see <xref linkend="control-bus"/>) functionality.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<emphasis>Control Bus</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
One of the way to manage the router mappings is through the <ulink url="http://www.eaipatterns.com/ControlBus.html">Control Bus</ulink>
|
||||
One way to manage the router mappings is through the <ulink url="http://www.eaipatterns.com/ControlBus.html">Control Bus</ulink>
|
||||
pattern which exposes a Control Channel where you can send
|
||||
control messages to manage and monitor Spring Integration components, including routers.
|
||||
For more information about the Control Bus see <xref linkend="control-bus"/>. Typically you would send a control message asking to invoke a
|
||||
particular JMX operation on a particular managed component (e.g., router). The two managed operations (methods) that are
|
||||
specific to changing router resolution process are:
|
||||
particular operation on a particular managed component (e.g., router). The two managed operations (methods) that are
|
||||
specific to changing the router resolution process are:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><code>public void setChannelMapping(String channelIdentifier, String channelName)</code> -
|
||||
will allow you to add new or modify existing mapping of <code>channel identifier</code> to <code>channel name</code></para>
|
||||
will allow you to add a new or modify an existing mapping between <code>channel identifier</code> and <code>channel name</code></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><code>public void removeChannelMapping(String channelIdentifier)</code> -
|
||||
@@ -430,12 +435,11 @@ public List<String> route(@Header("orderStatus") OrderStatus status)</prog
|
||||
<code>channel identifier</code> and <code>channel name</code> </para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
For additional managed operations please refer to an <classname>AbstractMessageRouter</classname> for more detail
|
||||
</para>
|
||||
<para>
|
||||
You can also use your favorite JMX client (e.g., JConsole) and use those operations (methods) to change
|
||||
router configuration. For more information on Spring Integration management and monitoring please visit
|
||||
<xref linkend="jmx"/>.
|
||||
You can also expose a router instance with Spring's JMS support and then use your favorite JMX client (e.g., JConsole) to
|
||||
manage those operations (methods) for changing the router's configuration. For more information on Spring Integration
|
||||
management and monitoring please visit <xref linkend="jmx"/>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
|
||||
@@ -36,6 +36,8 @@ import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.integration.support.channel.BeanFactoryChannelResolver;
|
||||
import org.springframework.integration.support.channel.ChannelResolutionException;
|
||||
import org.springframework.integration.support.channel.ChannelResolver;
|
||||
import org.springframework.jmx.export.annotation.ManagedOperation;
|
||||
import org.springframework.jmx.export.annotation.ManagedResource;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -46,6 +48,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Mark Fisher
|
||||
* @author Oleg Zhurakousky
|
||||
*/
|
||||
@ManagedResource
|
||||
public abstract class AbstractMessageRouter extends AbstractMessageHandler {
|
||||
|
||||
private volatile MessageChannel defaultOutputChannel;
|
||||
@@ -102,7 +105,8 @@ public abstract class AbstractMessageRouter extends AbstractMessageHandler {
|
||||
this.channelIdentifierMap.putAll(channelIdentifierMap);
|
||||
}
|
||||
|
||||
public void setChannelMapping(String channelIdentifier, String channelName){
|
||||
@ManagedOperation
|
||||
public void setChannelMapping(String channelIdentifier, String channelName) {
|
||||
this.channelIdentifierMap.put(channelIdentifier, channelName);
|
||||
}
|
||||
|
||||
@@ -110,7 +114,8 @@ public abstract class AbstractMessageRouter extends AbstractMessageHandler {
|
||||
* Removes channel mapping for a give channel identifier
|
||||
* @param channelIdentifier
|
||||
*/
|
||||
public void removeChannelMapping(String channelIdentifier){
|
||||
@ManagedOperation
|
||||
public void removeChannelMapping(String channelIdentifier) {
|
||||
this.channelIdentifierMap.remove(channelIdentifier);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user