4.4 Namespace Support

Throughout the reference manual, you will see specific configuration examples for endpoint elements, such as router, transformer, service-activator, and so on. Most of these will support an "input-channel" attribute and many will support an "output-channel" attribute. After being parsed, these endpoint elements produce an instance of either the PollingConsumer or the EventDrivenConsumer depending on the type of the "input-channel" that is referenced: PollableChannel or SubscribableChannel respectively. When the channel is pollable, then the polling behavior is determined based on the endpoint element's "poller" sub-element. For example, a simple interval-based poller with a 1-second interval would be configured like this:

 <transformer input-channel="pollable"
              ref="transformer"
              output-channel="output">
     <poller>
         <interval-trigger interval="1000"/>
     </poller>
</transformer>

For a poller based on a Cron expression, use the "cron-trigger" child element instead:

 <transformer input-channel="pollable"
              ref="transformer"
              output-channel="output">
     <poller>
         <cron-trigger expression="*/10 * * * * MON-FRI"/>
     </poller>
 </transformer>

If the input channel is a PollableChannel, then the poller configuration is required. Specifically, as mentioned above, the 'trigger' is a required property of the PollingConsumer class. Therefore, if you omit the "poller" sub-element for a Polling Consumer endpoint's configuration, an Exception may be thrown. However, it is also possible to create top-level pollers in which case only a "ref" is required:

 <poller id="weekdayPoller">
     <cron-trigger expression="*/10 * * * * MON-FRI"/>
 </poller>

 <transformer input-channel="pollable"
              ref="transformer"
              output-channel="output">
    <poller ref="weekdayPoller"/>
 </transformer>

In fact, to simplify the configuration, you can define a global default poller. A single top-level poller within an ApplicationContext may have the default attribute with a value of "true". In that case, any endpoint with a PollableChannel for its input-channel that is defined within the same ApplicationContext and has no explicitly configured 'poller' sub-element will use that default.

 <poller id="defaultPoller" default="true" max-messages-per-poll="5">
     <interval-trigger interval="3" time-unit="SECONDS"/>
 </poller>

 <!-- No <poller/> sub-element is necessary since there is a default -->
 <transformer input-channel="pollable"
              ref="transformer"
              output-channel="output"/>

Spring Integration also provides transaction support for the pollers so that each receive-and-forward operation can be performed as an atomic unit-of-work. To configure transactions for a poller, simply add the <transactional/> sub-element. The attributes for this element should be familiar to anyone who has experience with Spring's Transaction management:

<poller>
    <interval-trigger interval="1000"/>
    <transactional transaction-manager="txManager"
                   propagation="REQUIRED"
                   isolation="REPEATABLE_READ"
                   timeout="10000"
                   read-only="false"/>
</poller>

The polling threads may be executed by any instance of Spring's TaskExecutor abstraction. This enables concurrency for an endpoint or group of endpoints. As a convenience, there is also namespace support for creating a simple thread pool executor. The <thread-pool-task-executor/> element defines attributes for common concurrency settings such as core-size, max-size, and queue-capacity. Configuring a thread-pooling executor can make a substantial difference in how the endpoint performs under load. These settings are available per-endpoint since the performance of an endpoint is one of the major factors to consider (the other major factor being the expected volume on the channel to which the endpoint subscribes). To enable concurrency for a polling endpoint that is configured with the XML namespace support, provide the 'task-executor' reference on its <poller/> element and then provide one or more of the properties shown below:

 <poller task-executor="pool"/>
     <interval-trigger interval="5" time-unit="SECONDS"/>
 </poller>

 <thread-pool-task-executor id="pool"
                            core-size="5"
                            max-size="25"
                            queue-capacity="20"
                            keep-alive-seconds="120"/>

If no 'task-executor' is provided, the consumer's handler will be invoked in the caller's thread. Note that the "caller" is usually the default TaskScheduler (see Section B.3, “Configuring the Task Scheduler”). Also, keep in mind that the 'task-executor' attribute can provide a reference to any implementation of Spring's TaskExecutor interface by specifying the bean name. The thread pool element is simply provided for convenience.

As mentioned in the background section for Polling Consumers above, you can also configure a Polling Consumer in such a way as to emulate event-driven behavior. With a long receive-timeout and a short interval-trigger, you can ensure a very timely reaction to arriving messages even on a polled message source. Note that this will only apply to sources that have a blocking wait call with a timeout. For example, the File poller does not block, each receive() call returns immediately and either contains new files or not. Therefore, even if a poller contains a long receive-timeout, that value would never be usable in such a scenario. On the other hand when using Spring Integration's own queue-based channels, the timeout value does have a chance to participate. The following example demonstrates how a Polling Consumer will receive Messages nearly instantaneously.

 <service-activator input-channel="someQueueChannel"
        output-channel="output">  
     <poller receive-timeout="30000">
         <interval-trigger interval="10"/>
     </poller>
 </service-activator>

Using this approach does not carry much overhead since internally it is nothing more then a timed-wait thread which does not require nearly as much CPU resource usage as a thrashing, infinite while loop for example.