From a3c4099c6c83ee4eaeaaa0267e1a93265c75ec11 Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Mon, 22 Nov 2010 15:10:40 -0500 Subject: [PATCH] INT-1552 doc polishing, and added @ManagedResource/@ManagedOperation on the AbstractMessageRouter (for dynamic control over mappings) --- docs/src/reference/docbook/router.xml | 92 ++++++++++--------- .../router/AbstractMessageRouter.java | 9 +- 2 files changed, 55 insertions(+), 46 deletions(-) diff --git a/docs/src/reference/docbook/router.xml b/docs/src/reference/docbook/router.xml index 68768f138a..5a467735b8 100644 --- a/docs/src/reference/docbook/router.xml +++ b/docs/src/reference/docbook/router.xml @@ -17,7 +17,7 @@ A PayloadTypeRouter will send Messages to the channel as defined by payload-type mappings. - + @@ -26,10 +26,11 @@ ]]> - Configuration of PayloadTypeRouter is also supported via the namespace provided by Spring Integration (see ), - which essentially simplifies configuration by combining <router/> configuration and its corresponding implementation defined using <bean/> element + Configuration of the PayloadTypeRouter is also supported via the namespace provided by Spring Integration (see ), + which essentially simplifies configuration by combining the <router/> configuration and its corresponding implementation + defined using a <bean/> element into a single and more concise configuration element. - The example below demonstrates a PayloadTypeRouter configuration which is equivalent to the one above using Spring Integration's namespace support: + The example below demonstrates a PayloadTypeRouter configuration which is equivalent to the one above using the namespace support: @@ -42,7 +43,7 @@ HeaderValueRouter A HeaderValueRouter will send Messages to the channel based on the individual header value mappings. - When HeaderValueRouter is created it is initialized with the name of the header to be evaluated. + When a HeaderValueRouter is created it is initialized with the name of the header to be evaluated. The value of the header could be one of two things: 1. Arbitrary value @@ -51,11 +52,11 @@ 2. Channel name - 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. - Spring Integration provides a simple namespace-based XML configuration to configure HeaderValueRouter. - The example below demonstrates two types of namespace-based configuration of HeaderValueRouter. + Spring Integration provides a simple namespace-based XML configuration to configure a HeaderValueRouter. + The example below demonstrates two types of namespace-based configuration for the HeaderValueRouter. 1. Configuration where mapping of header values to channels is required @@ -69,7 +70,8 @@ exception. If you want to suppress such exceptions and send unresolved messages to the default output channel (identified with the default-output-channel attribute) set ignore-channel-name-resolution-failures to true. Normally, messages for which the header value is not explicitly mapped to a channel will be sent to the default-output-channel. - However, in cases where the header value is mapped to a channel name but the channel cannot be resolved, setting ignore-channel-name-resolution-failures + However, in cases where the header value is mapped to a channel name but the channel cannot be resolved, setting + the ignore-channel-name-resolution-failures attribute to true will result in routing such messages to the default-output-channel. @@ -106,7 +108,7 @@ - Spring Integration also provides namespace support for RecipientListRouter configuration (see ) + Spring Integration also provides namespace support for the RecipientListRouter configuration (see ) as the example below demonstrates. @@ -120,12 +122,14 @@ 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 for more information. - Another convenient option to configure RecipientListRouter is to use Spring Expression Language (SpEL) support + Another convenient option when configuring a RecipientListRouter 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. @@ -142,7 +146,7 @@
Configuring Router
- Configuring Router with XML + Configuring a Content Based Router with XML The "router" element provides a simple way to connect a router to an input channel and also accepts the optional default-output-channel attribute. The ref attribute references the bean name of a custom Router implementation @@ -173,17 +177,17 @@ - Routers and Spring Expression Language (SpEL) + Routers and the Spring Expression Language (SpEL) 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 SpEL to implement simple computations that previously required a custom POJO router. ]]> In the above configuration the result channel will be computed by the SpEL expression which simply concatenates the value - of the payload with the literal 'Channel' + of the payload with the literal String 'Channel'. @@ -203,7 +207,7 @@
- Configuring Router with Annotations + Configuring a Router with Annotations When using @Router to annotate a method, the method may return either a MessageChannel or String type. In the latter case, @@ -363,7 +367,7 @@ public List<String> route(@Header("orderStatus") OrderStatus status)HeaderValueRouter we clearly see that there is no mapping sub element: ]]> - 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? What this means is that Step 2 is now an optional step. If mapping is not defined then the channel identifier @@ -376,53 +380,54 @@ public List<String> route(@Header("orderStatus") OrderStatus status) For Example: - In the above configuration lets assume that the testHeader value is 'kermit' which is now a channel identifier + In the above configuration let's assume that the testHeader value is 'kermit' which is now a channel identifier (Step 1). Since there is no mapping in this router, resolving this channel identifier to a channel name (Step 2) is impossible and this channel identifier is now treated as channel name. However what if - there was a mapping but for a different value, the end result would still be the same and that is: - if new value can not be determined through the process of resolving 'channel identifier' to a 'channel name', - such 'channel identifier' becomes 'channel name' + there was a mapping but for a different value? The end result would still be the same and that is: + if new value cannot be determined through the process of resolving the 'channel identifier' to a 'channel name', + such 'channel identifier' becomes 'channel name'. - So all that is left is for Step 3 to resolve channel name ('kermit') to an actual instance of the - MessageChannel identified by this name. That will be done via a default - ChannelResolver implementation which is a BeanFactoryChannelResolver which - basically does a bean lookup by the name provided. So now all messages which contain the header/value pair as testHeader=kermit - are going to be routed to a 'kermit' MessageChannel. + So all that is left is for Step 3 to resolve the channel name ('kermit') to an actual instance of the + MessageChannel identified by this name. That will be done via the default + ChannelResolver implementation which is a BeanFactoryChannelResolver. It + basically does a bean lookup for the name provided. So now all messages which contain the header/value pair as testHeader=kermit + are going to be routed to a MessageChannel whose bean name (id) is 'kermit'. - 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 channel identifier map, then you - could just introduce a new mapping where header/value pair is now kermit=simpson, thus allowing Step 2 to treat - 'kermit' as channel identifier while resolving it to 'simpson' as channel name . + could just introduce a new mapping where the header/value pair is now kermit=simpson, thus allowing Step 2 to treat + 'kermit' as a channel identifier while resolving it to 'simpson' as the channel name . The same obviously applies for PayloadTypeRouter where you can now remap or remove a particular payload type - mapping, and every other router including expression-based routers since their computed value - will now have a chance to go through Step 2 to be aditionally resolved to the actual channel name. + mapping. In fact, it applies to every other router including expression-based routers since their computed values + will now have a chance to go through Step 2 to be additionally resolved to the actual channel name. - 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 AbstractMessageRouter (which includes all framework defined routers) is a Dynamic Router simply because the - channelIdentiferMap is defined at the AbstractMessageRouter with convenient accessors - and modifiers exposed as public methods allowing you to change/add/remove router mapping at runtime via JMX (see ) or - the ControlBus (see ) functionality.  + channelIdentiferMap is defined at the AbstractMessageRouter 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 ) or the Spring Integration ControlBus (see ) functionality.  Control Bus - One of the way to manage the router mappings is through the Control Bus + One way to manage the router mappings is through the Control Bus 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 . 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: public void setChannelMapping(String channelIdentifier, String channelName) - - will allow you to add new or modify existing mapping of channel identifier to channel name + will allow you to add a new or modify an existing mapping between channel identifier and channel name public void removeChannelMapping(String channelIdentifier) - @@ -430,12 +435,11 @@ public List<String> route(@Header("orderStatus") OrderStatus status)channel identifier and channel name - For additional managed operations please refer to an AbstractMessageRouter for more detail - 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 - . + 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 .
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/router/AbstractMessageRouter.java b/spring-integration-core/src/main/java/org/springframework/integration/router/AbstractMessageRouter.java index 1a2c42e7d4..731ac17cbb 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/router/AbstractMessageRouter.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/router/AbstractMessageRouter.java @@ -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); }