INT-1558 added XMPP documentation

This commit is contained in:
Oleg Zhurakousky
2010-11-11 08:03:45 -05:00
parent 6560444c16
commit 374f70fb31

View File

@@ -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&lt;String&gt;</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>