Merge branch 'master' into buildSrc-extraction
Conflicts: spring-integration-twitter/src/main/java/org/springframework/integration/twitter/core/Twitter4jTemplate.java
This commit is contained in:
@@ -584,6 +584,49 @@ public Message<?> receive(final PollableChannel<?> channel) { ... }]]></programl
|
||||
<emphasis>true</emphasis> enables logging of all headers in addition to the payload.
|
||||
</tip>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<emphasis>A little more on Wite Tap</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
One of the common misconception about the wire tap and some time other similar components (<xref linkend="message-publishing-config"/>)
|
||||
that they are asynchronous in nature. Wire-tap as a component is neither <emphasis>sync</emphasis> nor <emphasis>async</emphasis>.
|
||||
In fact non of the components in SI are <emphasis>sync</emphasis> or <emphasis>async</emphasis> except for. . . well read on.
|
||||
|
||||
What makes certain parts of the message flow <emphasis>sync</emphasis> or <emphasis>async</emphasis> is the <emphasis>Message Channel</emphasis>
|
||||
abstraction. That is why from the inception of the framework we always emphasize the need and the value of the <emphasis>Message Channel</emphasis>
|
||||
and that is why Spring Integration is the only framework at the time of writing where <emphasis>Message Channel</emphasis>
|
||||
is a "first class citizen" of the framework (not an internal realization of EIP pattern) fulle exposed to you - the end user.
|
||||
|
||||
So, Wire-tap component is ONLY responsible to perform the following 3 tasks:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>wire-tap into a message flow by tapping into a channel (e.g., channelA)</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>grab a copy of a message</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>send it to another channel (e.g., channelB)</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
|
||||
Look at it as a variation of the Bridge (nothing more). But by bridging one channel with another wire-tap is essentially
|
||||
initiates (forks) another message flow. Is this flow <emphasis>synchronous</emphasis> or <emphasis>asynchronous</emphasis>?
|
||||
That is the ultimate question and the answer simply depends on the type of <emphasis>Message Channel</emphasis> 'channelB' is.
|
||||
And as you know we have: <emphasis>Direct Channel</emphasis>, <emphasis>Pollable Channel</emphasis> and <emphasis>Executor Channel</emphasis>.
|
||||
The last two do break the thread boundary making communication via such channels <emphasis>asynchronous</emphasis> simply because
|
||||
the dispatching of the message from the channel happens on the different thread then the one that sent the message to that channel
|
||||
and that is what is going to make your wire-tap flow <emphasis>sync</emphasis> or <emphasis>async</emphasis>.
|
||||
It is consistent with other components within the framework (e.g., Message Publisher) and if you think about it its in a way
|
||||
brings a level of simplicity by sparing you form worrying in advance (other then writing thread safe code) wether a
|
||||
particular piece of code should be implemented as <emphasis>sync</emphasis> or <emphasis>async</emphasis>. In fact its always neither,
|
||||
the code is just a function. The actual wiring of two pieces of code (component A and component B) via <emphasis>Message Channel</emphasis>
|
||||
is what's going to make their collaboration <emphasis>sync</emphasis> or <emphasis>async</emphasis>. You may even want to change
|
||||
from <emphasis>sync</emphasis> to <emphasis>async</emphasis> in the future and <emphasis>Message Channel</emphasis> is what's going
|
||||
to allow you to do it swiftly without ever touching the code
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<note>
|
||||
|
||||
85
docs/src/reference/docbook/claim-check.xml
Normal file
85
docs/src/reference/docbook/claim-check.xml
Normal file
@@ -0,0 +1,85 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<section xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="claim-check"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>Claim Check</title>
|
||||
|
||||
<section id="claim-check-introduction">
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
In the earlier sections we've covered several Content Enricher type components that helps you deal with situations where a
|
||||
message is missing a piece of data. We also discussed Content Filtering which lets you remove uninteresting data items from a message.
|
||||
However there are times when we want to remove some data temporarily. For example; In a distributed system we may receive a
|
||||
Message with a very large payload. Some intermittent message processing steps may not need access to this payload and some may only
|
||||
need to access parts of the payload so carrying the large Message through each processing step may cause performance degradation
|
||||
and makes debugging harder.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<link href="http://www.eaipatterns.com/StoreInLibrary.html">Claim Check</link> pattern describes mechanism that allows you
|
||||
to store data in a well known place while only maintaining a pointer (Claim Check) to where that data is and pass such
|
||||
pointer around as a payload of a new Message allowing any component within the message flow to get the actual data as soon as
|
||||
it needs it. This approach is very similar to the Certified Mail process where you'll get Claim Check in your mailbox and
|
||||
would have to go to the Post Office to claim your actual package or mail.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Spring Integration provides two types of Claim Check transformers - <emphasis>Incoming Claim Check Transformer</emphasis> and
|
||||
<emphasis>Outgoing Claim Check Transformer</emphasis> as well as convenient namespace-based mechanism to configure them.
|
||||
</para>
|
||||
|
||||
<section id="claim-check-in">
|
||||
<title>Incoming Claim Check Transformer</title>
|
||||
|
||||
<para>
|
||||
<emphasis>Incoming Claim Check Transformer</emphasis> - will transform incoming Message by storing it in the Message Store
|
||||
identified by <code>message-store</code> attribute.
|
||||
|
||||
<programlisting language="xml"><![CDATA[<int:claim-check-in id="checkin"
|
||||
input-channel="checkinChannel"
|
||||
message-store="testMessageStore"
|
||||
output-channel="checkoutChannel"/>]]></programlisting>
|
||||
|
||||
In the above configuration the Message that is received on the <code>input-channel</code> will be persisted to the
|
||||
Message Store identified with <code>message-store</code> attribute and indexed with generated ID. That ID is the Claim Check for that Message.
|
||||
This Claim Check will also become the payload of the new (transformed) Message that will be sent to the <code>output-channel</code>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Now, lets assume that at some point you do need access to the actual Message. You can of course access the Message Store
|
||||
manually and get the contents of the Message or you can use the same approach as before except now you will be transforming
|
||||
the Claim Check to the actual Message by using <emphasis>Outgoing Claim Check Transformer</emphasis>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="claim-check-out">
|
||||
<title>Outgoing Claim Check Transformer</title>
|
||||
|
||||
<para>
|
||||
<emphasis>Incoming Claim Check Transformer</emphasis> allows you to transform a Message from the Message with just a Claim Check
|
||||
to the Message with the original content.
|
||||
<programlisting language="xml"><![CDATA[<claim-check-out id="checkout"
|
||||
input-channel="checkoutChannel"
|
||||
message-store="testMessageStore"/>]]></programlisting>
|
||||
|
||||
In the above configuration the Message that is received on the <code>input-channel</code> has a Claim Check as a payload
|
||||
and <emphasis>Outgoing Claim Check Transformer</emphasis> will transform it into an original Message by simply querying the
|
||||
Message store for a Message identified by a Claim Check provided and sending the new Message to the <code>output-channel</code>.
|
||||
</para>
|
||||
</section>
|
||||
<para>
|
||||
Although we rarely care about the protocol of the claim checks as long as they work, but it is still worth knowing that current
|
||||
implementation of the actual Claim Check (the pointer) in Spring Integration is UUID to ensure uniqueness.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<emphasis>A word on Message Store</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
<classname>org.springframework.integration.store.MessageStore</classname> is a strategy interface for storing and retrieving messages.
|
||||
Spring Integration provides two convenient implementations of it. <classname>SimpleMessageStore</classname> - In memory Map-based
|
||||
implementation (default, good for testing) and <classname>JdbcMessageStore</classname> - Implementation of <classname>MessageStore</classname>
|
||||
that uses relational database via JDBC.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
88
docs/src/reference/docbook/content-enrichment.xml
Normal file
88
docs/src/reference/docbook/content-enrichment.xml
Normal file
@@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<section xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="content-enricher"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>Content Enricher</title>
|
||||
|
||||
<section id="content-enricher-introduction">
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
Some time you may have a requirement to enhance a request with more information then it was
|
||||
provided by the target system. <link href="http://www.eaipatterns.com/DataEnricher.html">Content Enricher</link> pattern
|
||||
describes various scenarios as well as the component (Enricher), which allows you to address such requirements.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="header-enricher">
|
||||
<title>Header Enricher</title>
|
||||
|
||||
<para>
|
||||
If you only need to add headers to a Message, and they are not dynamically determined by the Message content,
|
||||
then referencing a custom implementation of the Transformer may be an overkill. For that reason,
|
||||
Spring Integration provides the <emphasis>Header Enricher</emphasis> which is exposed via <code><header-enricher></code> element.
|
||||
|
||||
<programlisting language="xml"><![CDATA[<int:header-enricher input-channel="in" output-channel="out">
|
||||
<int:header name="foo" value="123"/>
|
||||
<int:header name="bar" ref="someBean"/>
|
||||
</int:header-enricher>]]></programlisting>
|
||||
|
||||
</para>
|
||||
<para>
|
||||
<emphasis>Header Enricher</emphasis> also provides helpful sub-elements to set well known header names.
|
||||
<programlisting language="xml"><![CDATA[<int:header-enricher input-channel="in" output-channel="out">
|
||||
<int:error-channel ref="applicationErrorChannel"/>
|
||||
<int:reply-channel ref="quoteReplyChannel"/>
|
||||
<int:correlation-id value="123"/>
|
||||
<int:priority value="HIGHEST"/>
|
||||
<int:header name="bar" ref="someBean"/>
|
||||
</int:header-enricher>]]></programlisting>
|
||||
|
||||
In the above configuration you can clearly see that for well known headers such as <code>errorChannel</code>,
|
||||
<code>correlationId</code>, <code>priority</code>, <code>replyChannel</code>etc., instead of using generic <emphasis><header></emphasis>
|
||||
sub-element where you would have to provide both header 'name' and 'value', you can use convenient sub-elements
|
||||
allowing you to set those values directly.
|
||||
</para>
|
||||
<para>
|
||||
<emphasis>SpEL Support</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
In Spring Integration 2.0 we are introducing convenience of
|
||||
<link href="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/expressions.html">Spring Expression Language (SpEL)</link>
|
||||
to help configure many different components. <emphasis>Header Enricher</emphasis> is one of them.
|
||||
A lot of times, header value cannot be defined statically and has to be computed dynamically. That is why
|
||||
<emphasis>Header Enricher</emphasis> allows you to also specify bean 'ref' and 'method' that will calculate the
|
||||
header value. Let's look at the following configuration:
|
||||
|
||||
<programlisting language="xml"><![CDATA[<int:header-enricher input-channel="in" output-channel="out">
|
||||
<int:header name="foo" method="computeValue" ref="myBean"/>
|
||||
</int:header-enricher>
|
||||
|
||||
<bean id="myBean" class="foo.bar.MyBean"/>]]></programlisting>
|
||||
|
||||
<programlisting language="java"><![CDATA[public class MyBean{
|
||||
public String computeValue(String payload){
|
||||
return payload.toUpperCase() + "_US";
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
As you can see that the computation logic to determine the header value is actually pretty simple and the
|
||||
natural question would be is there a simpler way to accomplish this? And that is where SpEL shows its true power.
|
||||
|
||||
<programlisting language="xml"><![CDATA[<int:header-enricher input-channel="in" output-channel="out">
|
||||
<int:header name="foo" expression="payload.toUpperCase() + '_US'"/>
|
||||
</int:header-enricher>]]></programlisting>
|
||||
|
||||
As you can see, with SpEL for simple cases like above we no longer have to provide a separate class and configure
|
||||
it in the application context. All we need is to use <emphasis>expression</emphasis> attribute and provide a valid
|
||||
SpEL expression. You can also see that 'payload' and 'headers' are bound as variables to the SpEL Evaluation Context
|
||||
giving you full access to the incoming Message.
|
||||
</para>
|
||||
<para>
|
||||
<emphasis>Adapter specific Header Enrichers</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
As you go through the manual you will see that as an added convenience
|
||||
Spring Integration provides adapter specific Header Enrichers (e.g., MAIL, XMPP, etc.)
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
@@ -3,12 +3,78 @@
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>Feed Adapter</title>
|
||||
<para>
|
||||
Spring Integration provides support for Feed (RSS, Atom)
|
||||
Spring Integration provides support for Syndication via Feed Adapters
|
||||
</para>
|
||||
<section id="feed-intro">
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
TODO
|
||||
As we know Web syndication is a form of syndication where material such as news items, press releases that is
|
||||
available to any website is also made available via we feeds such as RSS, ATOM etc.
|
||||
</para>
|
||||
<para>
|
||||
Spring integration provides support for Web Syndication via FEED adapter which comes with a convenient
|
||||
namespace-based configuration.
|
||||
To configure FEED namespace include the following elements into the headers of your XML configuration file:
|
||||
|
||||
<programlisting language="xml"><![CDATA[xmlns:int-feed="http://www.springframework.org/schema/integration/feed"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/integration/feed
|
||||
http://www.springframework.org/schema/integration/feed/spring-integration-feed-2.0.xsd"]]></programlisting>
|
||||
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Feed Inbound Channel Adapter</title>
|
||||
<para>
|
||||
The only adapter that is really needed to provide support for retrieving feeds is an <emphasis>inbound channel adapter</emphasis>
|
||||
which allows you to subscribe to a particular URL. Below is the configuration for such adapter:
|
||||
|
||||
<programlisting language="xml"><![CDATA[<int-feed:inbound-channel-adapter id="feedAdapter"
|
||||
channel="feedChannel"
|
||||
url="http://feeds.bbci.co.uk/news/rss.xml">
|
||||
<int:poller fixed-rate="10000" max-messages-per-poll="100" />
|
||||
</int-feed:inbound-channel-adapter>]]></programlisting>
|
||||
|
||||
In the above configuration we are subscribing to a URL identified by <code>url</code> attribute.
|
||||
</para>
|
||||
<para>
|
||||
As news items are retrieved they will be converted to a Message and sent to a channel identified by <code>channel</code> attribute.
|
||||
The payload of such message will be <classname>com.sun.syndication.feed.synd.SyndEntry</classname> which encapsulates
|
||||
various data (i.e., content, dates, authors etc.) about a news item.
|
||||
</para>
|
||||
<para>
|
||||
You can also see that <emphasis>Inbound Feed Channel Adapter</emphasis> is a Polling consumer which means you have to
|
||||
provide a poller configuration. However, one important thing you must understand with regard to Feed sinc its inner-workings
|
||||
are slightly different then any other poling consumer. When Inbound Feed adapter is started it does the first poll and
|
||||
receives <classname>com.sun.syndication.feed.synd.SyndEntryyFeed</classname> which is an object that contains multiple
|
||||
<classname>SyndEntry</classname> objects. Each entry is stored in the local entry queue and is released based on
|
||||
the value in the <code>max-messages-per-poll</code> attribute where each Message will contain a single entry.
|
||||
If during retrieval of the entries from the entry queue the queue had become empty the adapter will attempt to update
|
||||
the Feed populating the queue with more entries (SyndEntry) if available, otherwise the next attempt to poll for a feed will
|
||||
be determined by the trigger of the poller (e.g., every 10 seconds in the above configuration).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<emphasis>Duplicate Entries</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
Polling for a Feed might result in the entries that have already been processed ("I already read that news item, why are you showing it to me again?").
|
||||
Spring Integration provides a convenient mechanism to eliminate the need to worry about duplicate entries.
|
||||
Each feed entry will have <emphasis>publish date</emphasis> field. Every time the new Message is generated and sent,
|
||||
Spring Integration will store the value of the <emphasis>publish date</emphasis> in the instance of the
|
||||
<classname>org.springframework.integration.store.MetadataStore</classname> which is a strategy interface designed to store various
|
||||
types of meta-data (e.g., publish date of the last feed entry that has been processed) to help components such as Feed to deal with
|
||||
duplicates.
|
||||
</para>
|
||||
<para>
|
||||
The default rule for locating this meta-data store is as follows; Spring Integration will look for a bean of type
|
||||
<classname>org.springframework.integration.store.MetadataStore</classname> in the ApplicationContext. If one found then it will be used,
|
||||
otherwise it will create a new instance of <classname>SimpleMetadataStore</classname> which is a simple in-memory implementation that
|
||||
will only persist meta-data within the life-cycle of the application context. This means that upon restart you may end up with
|
||||
duplicate entries. If you need to persist meta-data between Application Context restarts, you may use
|
||||
<classname>PropertiesPersistingMetadataStore</classname> which is a property file based persister or provide your own
|
||||
implementation of the <classname>MetedataStore</classname> interface (e.g.,JdbcMetadatStore) and configure it as bean in the Application Context.
|
||||
|
||||
<programlisting language="xml"><![CDATA[<bean class="org.springframework.integration.store.PropertiesPersistingMetadataStore"/>]]></programlisting>
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
</section>
|
||||
|
||||
<section id="filter-namespace">
|
||||
<title>The <filter> Element</title>
|
||||
<title>Namespace support for Filter - <filter> Element</title>
|
||||
<para>
|
||||
The <filter> element is used to create a Message-selecting endpoint. In addition to "input-channel"
|
||||
and "output-channel" attributes, it requires a "ref". The "ref" may point to a MessageSelector implementation:
|
||||
|
||||
@@ -140,14 +140,18 @@
|
||||
the connection factory will not function without one). A reference to a server
|
||||
connection factory can also be provided to an outbound adapter; that adapter
|
||||
can then be used to send replies to incoming messages to the same connection.
|
||||
<tip>Reply messages will only be routed to the connection if the reply contains
|
||||
the header $ip_connection_id that was inserted into the original message by
|
||||
the connection factory.</tip>
|
||||
<tip>This is the extent of message correlation performed when sharing connection
|
||||
<tip>
|
||||
<para>Reply messages will only be routed to the connection if the reply contains
|
||||
the header ip_connection_id that was inserted into the original message by
|
||||
the connection factory.</para></tip>
|
||||
<tip>
|
||||
<para>This is the extent of message correlation performed when sharing connection
|
||||
factories between inbound and outbound adapters. Such sharing allows for
|
||||
asynchronous two-way communication over TCP. Only payload information is
|
||||
transferred using TCP; therefore any message correlation must be performed
|
||||
by downstream components such as aggregators or other endpoints.</tip>
|
||||
by downstream components such as aggregators or other endpoints.
|
||||
For more information refer to
|
||||
<xref linkend="ip-correlation">TCP Message Correlationn</xref></para></tip>
|
||||
</para>
|
||||
<para>
|
||||
A maximum of one adapter of each type may be given a reference to a connection
|
||||
@@ -406,7 +410,7 @@
|
||||
can process a single request/response at a time.
|
||||
</para>
|
||||
<para>
|
||||
The intbound gateway, after constructing a message with the incoming payload and sending
|
||||
The intbound gateway, after constructing a message with the incoming payload and sending
|
||||
it to the requestChannel, waits for a response and sends the payload
|
||||
from the response message by writing it to the connection.
|
||||
</para>
|
||||
@@ -416,9 +420,9 @@
|
||||
Communications over the connections are single-threaded. Users should be aware that only one
|
||||
message can be handled at a time and, if another thread attempts to send
|
||||
a message before the current response has been received, it will block until
|
||||
any previous requests are complete (or time out).
|
||||
If, however, the client connection factory is configured for single-use connections
|
||||
each new request gets its own connection and is processed immediately.
|
||||
any previous requests are complete (or time out).
|
||||
If, however, the client connection factory is configured for single-use connections
|
||||
each new request gets its own connection and is processed immediately.
|
||||
</para>
|
||||
<para>
|
||||
<programlisting language="xml"><![CDATA[
|
||||
@@ -444,6 +448,93 @@
|
||||
A simple oubound TCP gateway.
|
||||
</para>
|
||||
</section>
|
||||
<section id="ip-correlation">
|
||||
<title>TCP Message Correlation</title>
|
||||
<section>
|
||||
<title>Overview</title>
|
||||
<para>
|
||||
One goal of the IP Endpoints is to provide communication with systems other
|
||||
than another Spring Integration application. For this reason, only
|
||||
message payloads are sent
|
||||
and received. No message correlation is provided by the framework,
|
||||
except when using the gateways, or collaborating channel adapters on the
|
||||
server side. In the paragraphs below we discuss the various
|
||||
correlation techniques available to applications. In most cases, this
|
||||
requires specific application-level correlation of messages, even when
|
||||
message payloads contain some natural correlation data (such as an order
|
||||
number).
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Gateways</title>
|
||||
<para>
|
||||
The gateways will automatically correlate messages. However, an outbound
|
||||
gateway should only be used for relatively low-volume use.
|
||||
When the connection factory is configured for a single shared connection
|
||||
to be used for all message pairs ('single-use="false"'),
|
||||
only one message can be processed at a time.
|
||||
A new message will have to wait until the reply to the previous message has
|
||||
been received.
|
||||
When a connection factory is configured for each new message to use a new connection
|
||||
('single-use="true"'), the above restriction does not apply.
|
||||
While this may give higher throughput
|
||||
than a shared connection environment, it comes with the overhead of opening
|
||||
and closing a new connection for each message pair.
|
||||
</para>
|
||||
<para>
|
||||
Therefore, for high-volume messages, consider using a collaborating pair of
|
||||
channel adapters. However, you will need to provide collaboration logic.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Collaborating Outbound and Inbound Channel Adapters</title>
|
||||
<para>
|
||||
To achieve high-volume throughput (avoiding the pitfalls of using gateways
|
||||
as mentioned above) you may consider configuring a pair of collaborating
|
||||
outbound and inbound channel adapters. On the server side, message
|
||||
correlation is automatically handled by the adapters because the inbound
|
||||
adapter adds a header allowing the outbound adapter to determine which
|
||||
connection to use to send the reply message. On the client side, however,
|
||||
the application will have to provide its own correlation logic. This can
|
||||
be done in a number of ways.
|
||||
</para>
|
||||
<para>
|
||||
If the message payload has some natural correlation data, such as a
|
||||
transaction id or an order number, AND there is no need to retain any
|
||||
information (such as a reply channel header) from the original outbound message,
|
||||
the correlation is simple and would done at the application level in any case.
|
||||
</para>
|
||||
<para>
|
||||
If the message payload has some natural correlation data, such as a
|
||||
transaction id or an order number, but there is a need to retain some
|
||||
information (such as a reply channel header) from the original outbound message,
|
||||
you may need to retain a copy of the original outbound message (perhaps
|
||||
by using a publish-subscribe channel) and use an aggregator to recombine
|
||||
the necessary data.
|
||||
</para>
|
||||
<para>
|
||||
For either of the previous two paragraphs, if the payload has no natural
|
||||
correlation data, you may need to provide a transformer upstream of the
|
||||
outbound channel adapter to enhance the payload with such data. Such a
|
||||
transformer may transform the original payload to a new object containing
|
||||
both the original payload and some subset of the message headers. Of course,
|
||||
live objects (such as reply channels) from the headers can not be
|
||||
included in the transformed payload.
|
||||
</para>
|
||||
<para>
|
||||
If such a strategy is chosen you will need to ensure the connection factory
|
||||
has an appropriate serializer/deserializer pair to handle such a payload,
|
||||
such as the <classname>DefaultSerializer/Deserializer</classname> which use java
|
||||
serialization, or a custom serializer and deserializer.
|
||||
The <classname>ByteArray*Serializer</classname> options
|
||||
mentioned in <xref linkend="connection-factories">Connection Factories</xref>,
|
||||
including the default <classname>ByteArrayCrLfSerializer</classname>,
|
||||
do not support such payloads,
|
||||
unless the transformed payload is a <classname>String</classname> or
|
||||
<classname>byte[]</classname>,
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
<section id="ip-endpoint-reference">
|
||||
<title>IP Configuration Attributes</title>
|
||||
<para>
|
||||
@@ -611,7 +702,7 @@
|
||||
using nio, specifies the number of tcp fragments that are concurrently
|
||||
reassembled into complete messages.
|
||||
It only applies in this sense if task-executor is not configured.
|
||||
However, pool-size is also used for the server socket backlog,
|
||||
However, pool-size is also used for the server socket backlog,
|
||||
regardless of whether an external task executor is used. Defaults to 5.</entry>
|
||||
</row>
|
||||
<row>
|
||||
@@ -830,6 +921,70 @@
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
<table id="tcp-ib-adapter-attributes">
|
||||
<title>TCP Inbound Channel Adapter Attributes</title>
|
||||
<tgroup cols="3">
|
||||
<colspec align="left" />
|
||||
<colspec colnum="1" colname="col1" colwidth="1*"/>
|
||||
<colspec colnum="2" colname="col2" colwidth="1*"/>
|
||||
<colspec colnum="3" colname="col3" colwidth="3*"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry align="center">Attribute Name</entry>
|
||||
<entry align="left">Allowed Values</entry>
|
||||
<entry align="center">Attribute Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>channel</entry>
|
||||
<entry></entry>
|
||||
<entry>The channel to which inbound messages will be sent.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>connection-factory</entry>
|
||||
<entry></entry>
|
||||
<entry>If the connection factory has a type 'server', the factory is 'owned'
|
||||
by this adapter. If it has a type 'client', it is 'owned' by an
|
||||
outbound channel adapter and this adapter will receive any
|
||||
incoming messages on the connection created by the
|
||||
outbound adapter.</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
<table id="tcp-ob-adapter-attributes">
|
||||
<title>TCP Outbound Channel Adapter Attributes</title>
|
||||
<tgroup cols="3">
|
||||
<colspec align="left" />
|
||||
<colspec colnum="1" colname="col1" colwidth="1*"/>
|
||||
<colspec colnum="2" colname="col2" colwidth="1*"/>
|
||||
<colspec colnum="3" colname="col3" colwidth="3*"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry align="center">Attribute Name</entry>
|
||||
<entry align="left">Allowed Values</entry>
|
||||
<entry align="center">Attribute Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>channel</entry>
|
||||
<entry></entry>
|
||||
<entry>The channel on which outbound messages arrive.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>connection-factory</entry>
|
||||
<entry></entry>
|
||||
<entry>If the connection factory has a type 'client', the factory is
|
||||
'owned' by this adapter. If it has a type 'server', it is 'owned'
|
||||
by an inbound channel adapter and this adapter will attempt
|
||||
to correlate messages to the connection on which an
|
||||
original inbound message was received. </entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
<table id="tcp-ib-gateway-attributes">
|
||||
<title>TCP Inbound Gateway Attributes</title>
|
||||
<tgroup cols="3">
|
||||
@@ -846,9 +1001,26 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>port</entry>
|
||||
<entry>connection-factory</entry>
|
||||
<entry></entry>
|
||||
<entry>The port on which the gateway listens.</entry>
|
||||
<entry>The connection factory must be of type server. </entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>request-channel</entry>
|
||||
<entry></entry>
|
||||
<entry>The channel to which incoming messages will be sent.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>reply-channel</entry>
|
||||
<entry></entry>
|
||||
<entry>The channel on which reply messages may arrive. Usually replies will
|
||||
arrive on a temporary reply channel added to the inbound message
|
||||
header</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>reply-timeout</entry>
|
||||
<entry></entry>
|
||||
<entry>The time in milliseconds for which the gateway will wait for a reply.</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
@@ -869,9 +1041,32 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>host</entry>
|
||||
<entry>connection-factory</entry>
|
||||
<entry></entry>
|
||||
<entry>The host name or ip address of the destination.</entry>
|
||||
<entry>The connection factory must be of type client. </entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>request-channel</entry>
|
||||
<entry></entry>
|
||||
<entry>The channel on which outgoing messages will arrive.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>reply-channel</entry>
|
||||
<entry></entry>
|
||||
<entry>Optional. The channel to which reply messages may be sent if the
|
||||
original outbound message did not contain a reply channel header.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>reply-timeout</entry>
|
||||
<entry></entry>
|
||||
<entry>The time in milliseconds for which the gateway will wait for a reply.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>request-timeout</entry>
|
||||
<entry></entry>
|
||||
<entry>If a single-use connection factory is not being used, The time in milliseconds
|
||||
for which the gateway will wait to get access to the shared connection.</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
|
||||
@@ -5,5 +5,6 @@
|
||||
<title>Message Transformation</title>
|
||||
|
||||
<xi:include href="./transformer.xml"/>
|
||||
|
||||
<xi:include href="./content-enrichment.xml"/>
|
||||
<xi:include href="./claim-check.xml"/>
|
||||
</chapter>
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
</section>
|
||||
|
||||
<section id="transformer-namespace">
|
||||
<title>The <transformer> Element</title>
|
||||
<title>Namespace support for Transformer - <transformer> Element</title>
|
||||
<para>
|
||||
The <transformer> element is used to create a Message-transforming endpoint. In addition to "input-channel"
|
||||
and "output-channel" attributes, it requires a "ref". The "ref" may either point to an Object that contains the
|
||||
@@ -88,13 +88,8 @@
|
||||
|
||||
<payload-deserializing-transformer input-channel="bytesIn" output-channel="objectsOut"/>]]></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
If you only need to add headers to a Message, and they are not dynamically determined by Message content,
|
||||
then referencing a custom implementation may be overkill. For that reason, Spring Integration provides the
|
||||
'header-enricher' element. <programlisting language="xml"><![CDATA[ <header-enricher input-channel="in" output-channel="out">
|
||||
<header name="foo" value="123"/>
|
||||
<header name="bar" ref="someBean"/>
|
||||
</header-enricher>]]></programlisting>
|
||||
<para>
|
||||
<emphasis>Object-to-Map Transformer</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
As added convenience, Spring Integration also provides <emphasis>Object-to-Map</emphasis> and <emphasis>Map-to-Object</emphasis> transformers which
|
||||
@@ -161,7 +156,7 @@ public class Kid{
|
||||
</section>
|
||||
|
||||
<section id="transformer-annotation">
|
||||
<title>The @Transformer Annotation</title>
|
||||
<title>Annotation support for Transformer - @Transformer</title>
|
||||
<para>
|
||||
The <interfacename>@Transformer</interfacename> annotation can also be added to methods that expect either the
|
||||
<interfacename>Message</interfacename> type or the message payload type. The return value will be handled in the
|
||||
@@ -179,5 +174,22 @@ Order generateOrder(String productId, @Header("customerName") String customer) {
|
||||
}</programlisting>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="header-filter">
|
||||
<title>Header Filter</title>
|
||||
|
||||
Some time your transformation use case might be as simple as removing a few headers.
|
||||
For this type of use cases Spring Integration provides <emphasis>Header Filter</emphasis> which allows you to specify which header should be
|
||||
removed from the output Message.
|
||||
Basically <emphasis>Header Filter</emphasis> is the opposite of <emphasis>Header Enricher</emphasis>
|
||||
that is discussed in <xref linkend="header-enricher"/>
|
||||
|
||||
<programlisting language="xml"><![CDATA[<int:header-filter input-channel="inputChannel"
|
||||
output-channel="outputChannel" header-names="lastName, state"/>]]></programlisting>
|
||||
|
||||
As you can see, configuration of <emphasis>Header Filter</emphasis> is quite simple. It is a typical endpoint with input/output channels
|
||||
and <code>header-names</code> attribute which allows you to specify the names of the headers (delimited by coma if multiple)
|
||||
that need to be removed. So, in the above example headers with the name 'lastName' and 'state' will be removed.
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
@@ -7,10 +7,6 @@
|
||||
</para>
|
||||
<section id="xmpp-intro">
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
Spring Integration provides adapters for sending and receiving both XMPP messages and status changes from other
|
||||
entries in your roster as well as XMPP.
|
||||
</para>
|
||||
<para>
|
||||
XMPP describes a way for multiple agents to communicate with each other in a distributed system.
|
||||
The canonical use case is to send and receive instant messages, though XMPP can be, and is, used for far more
|
||||
@@ -19,12 +15,8 @@
|
||||
as broadcast status changes.
|
||||
</para>
|
||||
<para>
|
||||
<!--
|
||||
todo do we have to include TM for 'Facebook', 'GMail', and 'Gtalk'?
|
||||
-->
|
||||
XMPP provides the messaging fabric that underlies some of the biggest Instant Messaging networks in the world,
|
||||
including Google Talk (GTalk)
|
||||
- which is also available from within GMail - and Facebook Chat.
|
||||
including Google Talk (GTalk) - which is also available from within GMail - and Facebook Chat.
|
||||
There are many good open-source XMPP servers available. Two popular implementations are
|
||||
<ulink url="http://www.igniterealtime.org/projects/openfire/">
|
||||
<citetitle>Openfire</citetitle>
|
||||
@@ -33,76 +25,28 @@
|
||||
<ulink url="http://www.ejabberd.im">
|
||||
<citetitle>ejabberd</citetitle>
|
||||
</ulink>
|
||||
.
|
||||
</para>
|
||||
<para>
|
||||
In XMPP,
|
||||
<emphasis>rosters</emphasis>
|
||||
(the roster corresponds to the notion of a "buddy list" in your typical IM client) are used to manage a list of
|
||||
other agents ("contacts", or "buddies", in an IM client)
|
||||
in the system, called<emphasis>roster items</emphasis>.
|
||||
The roster item contains - at a minimum - the roster item's JID which is its unique ID on the network.
|
||||
An actor may subscribe to the state changes of another actor in the system. The subscription can be bidirectional,
|
||||
as well.
|
||||
The subscription settings determine whose status updates are broadcast, and to whom.
|
||||
These subscriptions are stored on the XMPP server, and are thus durable.
|
||||
|
||||
Spring integration provides support for XMPP via XMPP adapters which support sending and receiving both XMPP messages and
|
||||
status changes from other entries in your roster. As many other adapters, XMPP adapters come with a convenient namespace-based
|
||||
configuration.
|
||||
To configure XMPP namespace include the following elements into the headers of your XML configuration file:
|
||||
|
||||
<programlisting language="xml"><![CDATA[xmlns:xmpp="http://www.springframework.org/schema/integration/xmpp"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/integration/xmpp
|
||||
http://www.springframework.org/schema/integration/xmpp/spring-integration-xmpp-2.0.xsd"]]></programlisting>
|
||||
|
||||
</para>
|
||||
|
||||
|
||||
</section>
|
||||
<section id="xmpp-config">
|
||||
<title>Using The Spring Integration XMPP Namespace
|
||||
</title>
|
||||
<para>
|
||||
Using the Spring Integration XMPP namespace support is simple.
|
||||
|
||||
Its use is like any other module in the Spring framework: import the XML schema, and use it to define elements.
|
||||
|
||||
A prototypical XMPP-based integration might feature the following header. We won't repeat this in subsequent
|
||||
examples, because it is uninteresting.
|
||||
|
||||
|
||||
<programlisting lang="xml"><![CDATA[
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<beans:beans
|
||||
xmlns="http://www.springframework.org/schema/integration"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:p="http://www.springframework.org/schema/p"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xmlns:xmpp="http://www.springframework.org/schema/integration/xmpp"
|
||||
xmlns:tool="http://www.springframework.org/schema/tool"
|
||||
xmlns:lang="http://www.springframework.org/schema/lang"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/integration/xmpp
|
||||
http://www.springframework.org/schema/integration/xmpp/spring-integration-xmpp.xsd
|
||||
http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/context
|
||||
http://www.springframework.org/schema/context/spring-context-3.0.xsd
|
||||
">
|
||||
...
|
||||
|
||||
</beans:beans>
|
||||
]]></programlisting>
|
||||
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
<section id="xmpp-connection">
|
||||
<title>XMPP Connection</title>
|
||||
<para>
|
||||
To participate in the network, an actor must connect to an XMPP server. Typically this requires - at a minimum - a
|
||||
<code>user</code>, a<code>password</code>, a<code>host</code>, and a<code>port</code>.
|
||||
Before using inbound or outbound XMPP adapters to participate in the XMPP network actor must establish XMPP connection. This
|
||||
connection object could be shared by all XMPP adapters connected to a particular account. Typically this requires - at a minimum -
|
||||
<code>user</code>, <code>password</code>, <code>host</code>.
|
||||
|
||||
To create an XMPP connection, you may use the XML namespace.
|
||||
To create a basic XMPP connection, you can utilize the convenience of the namespace.
|
||||
|
||||
<programlisting lang="xml"><![CDATA[<xmpp:xmpp-connection
|
||||
id="myConnection"
|
||||
@@ -111,8 +55,7 @@ http://www.springframework.org/schema/context/spring-context-3.0.xsd
|
||||
host="host"
|
||||
port="port"
|
||||
resource="theNameOfTheResource"
|
||||
subscription-mode="accept_all"
|
||||
/>
|
||||
subscription-mode="accept_all"/>
|
||||
]]></programlisting>
|
||||
</para>
|
||||
</section>
|
||||
@@ -120,218 +63,62 @@ http://www.springframework.org/schema/context/spring-context-3.0.xsd
|
||||
<section id="xmpp-messages">
|
||||
<title>XMPP Messages</title>
|
||||
<section id="xmpp-message-inbound-channel-adapter">
|
||||
<title>Inbound Message Adapter</title>
|
||||
<title>Inbound Message Channel Adapter</title>
|
||||
<para>The Spring Integration adapters support receiving messages from other users in the system. To do this, the
|
||||
adapter "logs in" as a user on your behalf and receives the messages sent to that user. Those messages are then
|
||||
<emphasis>Inbound Message Channel Adapter</emphasis> "logs in" as a user on your behalf and receives the messages sent to that user. Those messages are then
|
||||
forwarded to your Spring Integration client.
|
||||
The payload of the inbound Spring Integration message may be of the raw type<classname>
|
||||
org.jivesoftware.smack.packet.Message</classname>, or of the type
|
||||
<classname>java.lang.String</classname>
|
||||
- which is the type of the raw<code>
|
||||
Message</code>'s
|
||||
<code>body</code>
|
||||
property -
|
||||
depending on whether you specify
|
||||
<code>extract-payload</code>
|
||||
on the adapter's configuration or not.
|
||||
Inbound Messages are typically small and are text-oriented. Messages received using the adapter have
|
||||
a pretty standard layout, with known headers (all headers have keys defined on<classname>
|
||||
org.springframework.integration.xmpp.XmppHeaders</classname>):
|
||||
</para>
|
||||
|
||||
<table>
|
||||
<title>Header Values</title>
|
||||
|
||||
<tgroup cols="2">
|
||||
|
||||
<colspec colname="c1"/>
|
||||
<colspec colname="c2"/>
|
||||
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Header Name</entry>
|
||||
<entry>What It Describes</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>XmppHeaders.TYPE</entry>
|
||||
<entry>The value of the
|
||||
the
|
||||
<code>
|
||||
org.jivesoftware.smack.packet.Message.Type
|
||||
</code>
|
||||
enum that describes the inbound message. Possible values are:
|
||||
<code>normal</code>,
|
||||
<code>chat</code>,
|
||||
<code>groupchat</code>,
|
||||
<code>headline</code>,
|
||||
<code>error</code>.
|
||||
</entry>
|
||||
|
||||
</row>
|
||||
<row>
|
||||
<entry>XmppHeaders.CHAT</entry>
|
||||
<entry>A reference to the
|
||||
<code>org.jivesoftware.smack.Chat</code>
|
||||
class which represents the
|
||||
threaded conversation containing the message.
|
||||
</entry>
|
||||
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
|
||||
</table>
|
||||
|
||||
|
||||
<para>
|
||||
This adapter requires a reference to an XMPP Connection. You may
|
||||
use the
|
||||
<link linkend="xmpp-connection">xmpp-connection</link>
|
||||
element to define one.
|
||||
|
||||
An example might look as follows:
|
||||
|
||||
<programlisting lang="xml"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<beans:beans ... >
|
||||
|
||||
<context:component-scan
|
||||
base-package="com.myxmppclient.inbound"/>
|
||||
|
||||
<context:property-placeholder
|
||||
location="#{ systemProperties['user.home'] }/xmpp/xmppclient.properties"/>
|
||||
|
||||
<channel id="xmppInbound"/>
|
||||
|
||||
<xmpp:xmpp-connection
|
||||
id="testConnection"
|
||||
...
|
||||
/> ]]>
|
||||
|
||||
<emphasis><![CDATA[<xmpp:message-inbound-channel-adapter
|
||||
channel="xmppInbound"
|
||||
xmpp-connection="testConnection"/>
|
||||
]]></emphasis><![CDATA[
|
||||
<service-activator input-channel="xmppInbound"
|
||||
ref="xmppMessageConsumer"/>
|
||||
|
||||
</beans:beans>]]></programlisting>
|
||||
|
||||
|
||||
<classname>java.lang.String</classname> if you set <code>extract-payload</code> value attribute to 'true'
|
||||
when configuring an adapter.
|
||||
Configuration support for XMPP <emphasis>Inbound Message Channel Adapter</emphasis> is provided via <code>message-inbound-channel-adapter</code> element.
|
||||
|
||||
<programlisting language="xml"><![CDATA[<xmpp:message-inbound-channel-adapter id="xmppInboundAdapter"
|
||||
channel="xmppInbound"
|
||||
xmpp-connection="testConnection"
|
||||
extract-payload="false"
|
||||
auto-startup="true"/>]]></programlisting>
|
||||
|
||||
As you can see amongst the usual attributes this adapter also requires a reference to an XMPP Connection.
|
||||
</para>
|
||||
<para>
|
||||
In this example, the message is received from the XMPP adapter and passed to a
|
||||
<code>service-activator</code>
|
||||
component. Here's the declaration of the<code>service-activator</code>.
|
||||
<programlisting lang="java"><![CDATA[package com.myxmppclient.inbound ;
|
||||
|
||||
import org.jivesoftware.smack.packet.Message;
|
||||
|
||||
import org.springframework.integration.annotation.ServiceActivator;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class XmppMessageConsumer {
|
||||
|
||||
@ServiceActivator
|
||||
public void consume(Message input) throws Throwable {
|
||||
String text = input.getBody();
|
||||
System.out.println( "Received message: " + text ) ;
|
||||
}
|
||||
|
||||
}
|
||||
]]></programlisting>
|
||||
It is also important to mention that XMPP inbound adapter is an <emphasis>event driven adapter</emphasis> and a <classname>LifeCycle</classname> object.
|
||||
When started it will register a <classname>PacketListener</classname> which will listen for the incoming XMPP Messages forwarding them to the underlying
|
||||
adapter which will convert them to Spring Integration Messages and send them to the <classname>output-channel</classname>. It will
|
||||
unregister <classname>PacketListener</classname> when it is stopped.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<section id="xmpp-message-outbound-channel-adapter">
|
||||
<title>Outbound Message Adapter</title>
|
||||
<para>
|
||||
You may also send messages to other users on XMPP using the
|
||||
<code>outbound-message-channel-adapter</code>
|
||||
adapter. The is configured like the
|
||||
|
||||
<link linkend="xmpp-message-inbound-channel-adapter">xmpp-message-inbound-channel-adapter</link>. The
|
||||
adapter takes an
|
||||
<code>xmpp-connection</code>
|
||||
reference.
|
||||
|
||||
|
||||
Here is a (necessarily) contrived example solution using the outbound adapter.
|
||||
|
||||
<programlisting lang="xml"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<beans:beans ... >
|
||||
|
||||
<context:component-scan
|
||||
base-package="com.myxmppproducer.outbound"/>
|
||||
|
||||
<context:property-placeholder
|
||||
location="#{ systemProperties['user.home'] }/xmpp/xmppclient.properties"/>
|
||||
|
||||
<beans:bean id="xmppProducer"
|
||||
class="com.myxmppproducer.outbound.XmppMessageProducer"
|
||||
p:recipient="${user.2.login}"/>
|
||||
|
||||
<poller default="true" fixed-rate="10000"/>
|
||||
|
||||
<xmpp:xmpp-connection
|
||||
id="testConnection"
|
||||
...
|
||||
/>
|
||||
|
||||
<inbound-channel-adapter ref="xmppProducer"
|
||||
channel="outboundChannel"/>
|
||||
|
||||
<channel id="outboundChannel"/>
|
||||
|
||||
<xmpp:message-outbound-channel-adapter
|
||||
channel="outboundChannel"
|
||||
xmpp-connection="testConnection"/>
|
||||
|
||||
</beans:beans>]]>
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
|
||||
The adapter expects as its input - at a minimum - a payload of type <classname>java.lang.String</classname>, and
|
||||
a header value
|
||||
for
|
||||
<code>XmppHeaders.CHAT_TO_USER</code>
|
||||
that specifies to which the user the payload body should be sent to.
|
||||
To create a message destined for the<code>outbound-message-channel-adapter</code>, you might use the following
|
||||
Java code:
|
||||
|
||||
<programlisting lang="java">
|
||||
<![CDATA[
|
||||
Message<String> xmppOutboundMsg = MessageBuilder.withPayload("Hello, world!" )
|
||||
.setHeader(XmppHeaders.CHAT_TO_USER, "userhandle")
|
||||
.build();
|
||||
]]></programlisting>
|
||||
|
||||
</para>
|
||||
<para>
|
||||
It's easy enough to use Java to update the <code>XmppHeaders.CHAT_TO_USER</code> header, and this has the advantage of dynamically updating the header at runtime in Java code.
|
||||
If, however, the target is more static in nature, you can
|
||||
configure it using the
|
||||
XMPP enricher support. Here is an example using the enricher. The enricher enriches the Spring Integration
|
||||
message
|
||||
to support the header values that the outbound XMPP adapters expect.
|
||||
<programlisting lang="xml">
|
||||
<![CDATA[
|
||||
<channel id="input"/>
|
||||
<channel id="output"/>
|
||||
|
||||
<xmpp:header-enricher input-channel="input" output-channel="output">
|
||||
<xmpp:message-to value="test1@example.org"/>
|
||||
</xmpp:header-enricher>
|
||||
]]></programlisting>
|
||||
</para>
|
||||
|
||||
<title>Outbound Message Channel Adapter</title>
|
||||
|
||||
<para>
|
||||
You may also send messages to other users on XMPP using the <emphasis>Outbound Message Channel Adapter</emphasis>.
|
||||
Configuration support for XMPP <emphasis>Outbound Message Channel Adapter</emphasis> is provided via <code>message-outbound-channel-adapter</code> element.
|
||||
|
||||
<programlisting language="xml"><![CDATA[<int-xmpp:message-outbound-channel-adapter id="outboundEventAdapter"
|
||||
channel="outboundEventChannel"
|
||||
xmpp-connection="testConnection"/>]]></programlisting>
|
||||
|
||||
The adapter expects as its input - at a minimum - a payload of type <classname>java.lang.String</classname>, and a header value
|
||||
for <classname>XmppHeaders.CHAT_TO_USER</classname> that specifies to which user the Message should be sent to. To
|
||||
create a message you might use the following Java code:
|
||||
|
||||
<programlisting language="java"><![CDATA[Message<String> xmppOutboundMsg = MessageBuilder.withPayload("Hello, XMPP!" )
|
||||
.setHeader(XmppHeaders.CHAT_TO_USER, "userhandle")
|
||||
.build();]]></programlisting>
|
||||
|
||||
Another mechanism of setting such header is by using the XMPP enricher support. Here is an example using the enricher.
|
||||
|
||||
<programlisting language="xml"><![CDATA[<int-xmpp:header-enricher input-channel="input" output-channel="output">
|
||||
<int-xmpp:message-to value="test1@example.org"/>
|
||||
</int-xmpp:header-enricher>]]></programlisting>
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
<section id="xmpp-presence">
|
||||
<title>XMPP Presence</title>
|
||||
|
||||
@@ -345,98 +132,114 @@ public class XmppMessageConsumer {
|
||||
|
||||
If you would like to receive notification, or notify others, of state changes, you can use Spring Integration's "presence" adapters.
|
||||
|
||||
</para> <para>
|
||||
The most important data for these adapters resides in the headers. The header keys are enumerated on
|
||||
the <code>org.springframework.integration.xmpp.XmppHeaders</code> class.
|
||||
|
||||
The header keys specific to these "presence" adapters start with the token "PRESENCE_".
|
||||
|
||||
Not all headers are available for both inbound and outbound.
|
||||
|
||||
</para> <table>
|
||||
<title>Header Values</title>
|
||||
|
||||
<tgroup cols="2">
|
||||
|
||||
<colspec colname="c1"/>
|
||||
<colspec colname="c2"/>
|
||||
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Header Name</entry>
|
||||
<entry>What It Describes</entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>XmppHeaders.PRESENCE_LANGUAGE</entry>
|
||||
<entry> The <code>java.lang.String</code> language in which the message was written.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>XmppHeaders.PRESENCE_PRIORITY</entry>
|
||||
<entry>
|
||||
The priority (int) of the message. Arbitrary, but it can be used to help assign relevance to a message which
|
||||
in turn might be used in its handling.
|
||||
</entry>
|
||||
|
||||
</row><row>
|
||||
<entry>XmppHeaders.PRESENCE_MODE</entry>
|
||||
<entry>
|
||||
An instance of the enum <code>org.jivesoftware.smack.packet.Presence.Mode</code> that has one of the following values:
|
||||
<code>chat,</code> <code>available,</code> <code>away,</code>
|
||||
<code>xa,</code> <code>dnd</code>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>XmppHeaders.PRESENCE_TYPE</entry>
|
||||
<entry>
|
||||
An instance of the enum <code>org.jivesoftware.smack.packet.Presence.Type</code>
|
||||
that has one of the following values:
|
||||
<code>available,</code> <code>unavailable,</code> <code>subscribe,</code> <code>subscribed,</code>
|
||||
<code>unsubscribe,</code> <code>unsubscribed,</code> and <code>error</code>.
|
||||
|
||||
|
||||
</entry>
|
||||
</row> <row>
|
||||
<entry>XmppHeaders.PRESENCE_STATUS</entry>
|
||||
<entry>
|
||||
A <code>java.lang.String</code> string representing the status of the agent. This corresponds to an agents "away" message.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>XmppHeaders.PRESENCE_FROM</entry>
|
||||
<entry>
|
||||
A <code>java.lang.String</code> string representing the handle of the user whose state is being received.
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
|
||||
</tbody>
|
||||
</tgroup>
|
||||
|
||||
</table>
|
||||
<section id="xmpp-presence-inbound-channel-adapter">
|
||||
<title>Inbound Presence Adapter</title>
|
||||
</para>
|
||||
|
||||
<section id="xmpp-roster-inbound-channel-adapter">
|
||||
<title>Inbound Roster Message Channel Adapter</title>
|
||||
<para>
|
||||
The first adapter supports receiving messages whenever an agent on your roster has updated its
|
||||
state. Most of the important data comes in through the headers.
|
||||
|
||||
Spring Integration provides <emphasis>Inbound Roster Message Channel Adapter</emphasis> which supports receiving Presence (Roster)
|
||||
events from other users in the system. To do this, the <emphasis>Inbound Roster Message Channel Adapter</emphasis> "logs in" as a user
|
||||
on your behalf, registers <classname>RosterListener</classname> and forwards received roster events as Messages to the channel
|
||||
identified by the <code>channel</code> attribute. The payload of the Message could either be <classname>org.jivesoftware.smack.packet.Presence</classname>
|
||||
object (see http://www.igniterealtime.org/builds/smack/docs/3.1.0/javadoc/org/jivesoftware/smack/packet/Presence.html) or
|
||||
<classname>java.util.Collection<String></classname> representing roster entries.
|
||||
</para>
|
||||
<para>
|
||||
Configuration support for XMPP <emphasis>Inbound Roster Message Channel Adapter</emphasis> is provided via
|
||||
<code>roster-event-inbound-channel-adapter</code> element.
|
||||
<programlisting language="xml"><![CDATA[<int-xmpp:roster-event-inbound-channel-adapter channel="outChannel"
|
||||
xmpp-connection="testConnection" auto-startup="false"/>]]></programlisting>
|
||||
|
||||
As you can see amongst the usual attributes this adapter also requires a reference to an XMPP Connection.
|
||||
It is also important to mention that this adapter is an event driven adapter and a <classname>LifeCycle</classname> object.
|
||||
It will register <classname>RosterListener</classname> when started and will unregister <classname>RosterListener</classname>
|
||||
when stopped.
|
||||
</para>
|
||||
</section>
|
||||
<section id="xmpp-presence-outbound-channel-adapter">
|
||||
<title>Outbound Presence Adapter</title>
|
||||
<para>TBD</para>
|
||||
|
||||
<section id="xmpp-roster-outbound-channel-adapter">
|
||||
<title>Outbound Roster Message Channel Adapter</title>
|
||||
|
||||
<para>
|
||||
Spring Integration also supports sending Presence (Roster) events to be seen by other users in the network. When you send a Message
|
||||
to the <emphasis>Outbound Roster Message Channel Adapter</emphasis> it extracts the payload which is expected to be of
|
||||
type <classname>org.jivesoftware.smack.packet.Presence</classname>
|
||||
(see http://www.igniterealtime.org/builds/smack/docs/3.1.0/javadoc/org/jivesoftware/smack/packet/Presence.html) and sends it to
|
||||
the XMPP Connection, thus advertising your presence events to the rest of the network.
|
||||
</para>
|
||||
<para>
|
||||
Configuration support for XMPP <emphasis>Outbound Roster Message Channel Adapter</emphasis> is provided via
|
||||
<code>roster-event-outbound-channel-adapter</code> element.
|
||||
|
||||
<programlisting language="xml"><![CDATA[<int-xmpp:roster-event-outbound-channel-adapter id="eventOutboundRosterChannel"
|
||||
xmpp-connection="testConnection"/>]]></programlisting>
|
||||
|
||||
It can also be a <emphasis>polling consumer</emphasis> (if it receives Messages from the Polling Channel) in which case you would
|
||||
need to register a Poller.
|
||||
|
||||
<programlisting language="xml"><![CDATA[<int-xmpp:roster-event-outbound-channel-adapter id="pollingOutboundRosterAdapter"
|
||||
xmpp-connection="testConnection"
|
||||
channel="pollingChannel">
|
||||
<int:poller fixed-rate="1000" max-messages-per-poll="1"/>
|
||||
</int-xmpp:roster-event-outbound-channel-adapter>]]></programlisting>
|
||||
|
||||
Similar to its Inbound counterpart it requires a reference to an XMPP Connection.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<!--<section id="xmpp-samples">
|
||||
<title>XMPP Samples</title>
|
||||
<section id="xmpp-appendices">
|
||||
<title>Appendices</title>
|
||||
|
||||
<para>
|
||||
Since Spring Integration XMPP support is based on Smack 3.1 API (http://www.igniterealtime.org/downloads/index.jsp), it is important
|
||||
to know a few details related to more complex configuration of XMPP Connection object.
|
||||
</para>
|
||||
<para>
|
||||
As it was said earlier the <code>xmpp-connection</code> namespace support is designed to simplify basic connection configuration and
|
||||
only supports few configuration attributes. However, <classname>org.jivesoftware.smack.ConnectionConfiguration</classname> object defines about 20
|
||||
attributes, and there is no real value of adding namespace support for all of them. So, for more complex connection configurations,
|
||||
simply configure <classname>XmppConnectionFactoryBean</classname> as a regular bean injecting
|
||||
<classname>org.jivesoftware.smack.ConnectionConfiguration</classname> as a constructor argument and configuring every property
|
||||
you may need. This way SSL or any other attributes could be set directly in a consistent Spring way. Example:
|
||||
|
||||
<programlisting language="xml"><![CDATA[<bean id="xmppConnection" class="org.springframework.integration.xmpp.XmppConnectionFactoryBean">
|
||||
<constructor-arg>
|
||||
<bean class="org.jivesoftware.smack.ConnectionConfiguration">
|
||||
<constructor-arg value="myServiceName"/>
|
||||
<property name="truststorePath" value="..."/>
|
||||
<property name="socketFactory" ref="..."/>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
<int:channel id="outboundEventChannel"/>
|
||||
|
||||
<int-xmpp:message-outbound-channel-adapter id="outboundEventAdapter"
|
||||
channel="outboundEventChannel"
|
||||
xmpp-connection="xmppConnection"/>]]></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
We really should have some samples...
|
||||
Another important aspect of Smack API is static initializers. For more complex cases (e.g., registering SASL Mechanism) you may need
|
||||
to execute certain static initializers. One of those static initializers is <classname>SASLAuthentication</classname> which allows
|
||||
you to register supported SASL mechanisms. For that level of complexity we would recommend Spring Javaconfig-style of XMPP Connection
|
||||
configuration where you can configure the entire component through Java code and execute all other necessary Java code including
|
||||
static initializers.
|
||||
|
||||
<programlisting language="java"><![CDATA[@Configuration
|
||||
public class CustomConnectionConfiguration {
|
||||
@Bean
|
||||
public XmppConnection knight() {
|
||||
SASLAuthentication.supportSASLMechanism("EXTERNAL", 0); // static initializer
|
||||
|
||||
ConnectionConfiguration config = new ConnectionConfiguration("localhost", 5223);
|
||||
config.setTrustorePath("path_to_truststore.jks");
|
||||
config.setSecurityEnabled(true);
|
||||
config.setSocketFactory(SSLSocketFactory.getDefault());
|
||||
conn = new XMPPConnection(config);
|
||||
}
|
||||
}]]></programlisting>
|
||||
For more information on Javaconfig style of Application Context configuration refere to the following section in Spring Reference Manual
|
||||
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans-java
|
||||
</para>
|
||||
</section>
|
||||
-->
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
|
||||
Reference in New Issue
Block a user