INT-3963: Add XMPP Extensions Support
JIRA: https://jira.spring.io/browse/INT-3963 * Update to Smack-4.1.6 * Introduce `stanza-filter` option for the `<int-xmpp:inbound-channel-adapter>` * Introduce `payloadExpression` for the complex and specific `stanza` parsing, e.g. GCM packets * Deprecate `extract-payload` in favor of `payload-expression` * Add `ChatMessageListeningEndpointTests` test for GCM protocol * Add `ChatMessageInboundChannelAdapterParser` test for new attributes * Document changes Polishing according PR comments Extract `#extension` SpEL variable Document the `#extension` SpEL variable
This commit is contained in:
committed by
Gary Russell
parent
956cf275e1
commit
f7c59b3b18
@@ -162,3 +162,8 @@ The `@InboundChannelAdapter` has now an alias `channel` attribute for regular `v
|
||||
In addition the target `SourcePollingChannelAdapter` components can now resolve the target `outputChannel` bean
|
||||
from its provided name (`outputChannelName` options) in late-binding manner.
|
||||
See <<annotations>> for more information.
|
||||
|
||||
==== XMPP changes
|
||||
|
||||
The XMPP Extensions (XEP) are now supported by the XMPP channel adapters.
|
||||
See <<xmpp-extensions>> for more information.
|
||||
|
||||
@@ -61,7 +61,6 @@ We also register a `ConnectionListener` which will log connection events if the
|
||||
The Spring Integration adapters support receiving chat messages from other users in the system.
|
||||
To do this, the _Inbound Message Channel Adapter_ "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 `org.jivesoftware.smack.packet.Message`, or of the type `java.lang.String` if you set the `extract-payload` attribute's value to 'true' when configuring an adapter.
|
||||
Configuration support for the XMPP _Inbound Message Channel Adapter_ is provided via the `inbound-channel-adapter` element.
|
||||
|
||||
[source,xml]
|
||||
@@ -69,7 +68,8 @@ Configuration support for the XMPP _Inbound Message Channel Adapter_ is provided
|
||||
<int-xmpp:inbound-channel-adapter id="xmppInboundAdapter"
|
||||
channel="xmppInbound"
|
||||
xmpp-connection="testConnection"
|
||||
extract-payload="false"
|
||||
payload-expression="getExtension('google:mobile:data').json"
|
||||
stanza-filter="stanzaFilter"
|
||||
auto-startup="true"/>
|
||||
----
|
||||
|
||||
@@ -80,6 +80,42 @@ When started it will register a `PacketListener` that will listen for incoming X
|
||||
It forwards any received messages to the underlying adapter which will convert them to Spring Integration Messages and send them to the specified `channel`.
|
||||
It will unregister the `PacketListener` when it is stopped.
|
||||
|
||||
Starting with _version 4.3_ the `ChatMessageListeningEndpoint` (and its `<int-xmpp:inbound-channel-adapter>`)
|
||||
supports a `org.jivesoftware.smack.filter.StanzaFilter` injection to be registered on the provided `XMPPConnection`
|
||||
together with an internal `StanzaListener` implementation.
|
||||
See their https://www.igniterealtime.org/builds/smack/docs/latest/javadoc/org/jivesoftware/smack/XMPPConnection.html#addAsyncStanzaListener%28org.jivesoftware.smack.StanzaListener,%20org.jivesoftware.smack.filter.StanzaFilter%29[JavaDocs] for more information.
|
||||
|
||||
Also with the _version 4.3_ the `payload-expression` has been introduced for the `ChatMessageListeningEndpoint`.
|
||||
The incoming `org.jivesoftware.smack.packet.Message` represents a root object of evaluation context.
|
||||
This option is useful in case of <<xmpp-extensions>>.
|
||||
For example, for the GCM protocol we can extract the body using expression:
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
payload-expression="getExtension('google:mobile:data').json"
|
||||
----
|
||||
|
||||
for the XHTML protocol:
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
payload-expression="getExtension(T(org.jivesoftware.smackx.xhtmlim.packet.XHTMLExtension).NAMESPACE).bodies[0]"
|
||||
----
|
||||
|
||||
To simplify the access to the Extension in the XMPP Message, the `extension` variable is added into the
|
||||
`EvaluationContext`.
|
||||
Note, it is done only when one and only one Extension is present in the Message.
|
||||
The samples above with the `namespace` manipulations can be simplified to something like:
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
payload-expression="#extension.json"
|
||||
payload-expression="#extension.bodies[0]"
|
||||
----
|
||||
|
||||
|
||||
NOTE: The `extract-payload` option has been deprecated in favor of the new `payload-expression` one.
|
||||
|
||||
[[xmpp-message-outbound-channel-adapter]]
|
||||
==== Outbound Message Channel Adapter
|
||||
|
||||
@@ -125,7 +161,7 @@ If you would like to receive notification, or notify others, of state changes, y
|
||||
|
||||
Spring Integration provides an _Inbound Presence Message Channel Adapter_ which supports receiving Presence events from other users in the system who happen to be on your Roster.
|
||||
To do this, the adapter "logs in" as a user on your behalf, registers a `RosterListener` and forwards received Presence update events as Messages to the channel identified by the `channel` attribute.
|
||||
The payload of the Message will be a `org.jivesoftware.smack.packet.Presence` object (see http://www.igniterealtime.org/builds/smack/docs/3.1.0/javadoc/org/jivesoftware/smack/packet/Presence.html).
|
||||
The payload of the Message will be a `org.jivesoftware.smack.packet.Presence` object (see https://www.igniterealtime.org/builds/smack/docs/latest/javadoc/org/jivesoftware/smack/packet/Presence.html).
|
||||
|
||||
Configuration support for the XMPP _Inbound Presence Message Channel Adapter_ is provided via the `presence-inbound-channel-adapter` element.
|
||||
|
||||
@@ -143,7 +179,7 @@ It will register a `RosterListener` when started and will unregister that `Roste
|
||||
==== Outbound Presence Message Channel Adapter
|
||||
|
||||
Spring Integration also supports sending Presence events to be seen by other users in the network who happen to have you on their Roster.
|
||||
When you send a Message to the _Outbound Presence Message Channel Adapter_ it extracts the payload, which is expected to be of type `org.jivesoftware.smack.packet.Presence` (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.
|
||||
When you send a Message to the _Outbound Presence Message Channel Adapter_ it extracts the payload, which is expected to be of type `org.jivesoftware.smack.packet.Presence` and sends it to the XMPP Connection, thus advertising your presence events to the rest of the network.
|
||||
|
||||
Configuration support for the XMPP _Outbound Presence Message Channel Adapter_ is provided via the `presence-outbound-channel-adapter` element.
|
||||
|
||||
@@ -218,7 +254,8 @@ public class CustomConnectionConfiguration {
|
||||
}
|
||||
----
|
||||
|
||||
For more information on the JavaConfig style of Application Context configuration, refer to the following section in the Spring Reference Manual: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans-java
|
||||
For more information on the JavaConfig style of Application Context configuration, refer to the following section
|
||||
in the http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-java[Spring Reference Manual].
|
||||
|
||||
[[xmpp-message-headers]]
|
||||
=== XMPP Message Headers
|
||||
@@ -256,3 +293,110 @@ Negated patterns get priority, so a list such as
|
||||
|
||||
IMPORTANT: If you have a user defined header that begins with `!` that you *do* wish to map, you need to escape it with
|
||||
`\` thus: `STANDARD_REQUEST_HEADERS,\!myBangHeader` and it *WILL* be mapped.
|
||||
|
||||
[[xmpp-extensions]]
|
||||
=== XMPP Extensions
|
||||
|
||||
The XMPP protocol stands for **eXstensible Messaging and Presence Protocol**.
|
||||
The "extensible" part is important.
|
||||
XMPP is based around XML, a data format that supports a concept known as _namespacing_.
|
||||
|
||||
Through namespacing, you can add bits to XMPP that are not defined in the original specifications.
|
||||
This is important because the XMPP specification deliberately describes only a set of core things like:
|
||||
|
||||
- How a client connects to a server
|
||||
- Encryption (SSL/TLS)
|
||||
- Authentication
|
||||
- How servers can communicate with each other to relay messages
|
||||
- and a few other basic building blocks.
|
||||
|
||||
Once you have implemented this, you have an XMPP client and can send any kind of data you like.
|
||||
But that's not the end.
|
||||
|
||||
For example, perhaps you decide that you want to include formatting in a message (bold, italic, etc.) which is not
|
||||
defined in the core XMPP specification.
|
||||
Well, you can make up a way to do that, but unless everyone else does it the same way as you,
|
||||
no other software will be able interpret it (they will just ignore namespaces they don't understand).
|
||||
|
||||
So the XMPP Standards Foundation (XSF) publishes a series of extra documents, known as
|
||||
http://xmpp.org/extensions/xep-0001.html[XMPP Enhancement Proposals] (XEPs).
|
||||
In general each XEP describes a particular activity (from message formatting, to file transfers, multi-user
|
||||
chats and many more), and they provide a standard format for everyone to use for that activity.
|
||||
|
||||
The Smack API provides many XEP implementations with its `extensions` and `experimental`
|
||||
http://www.igniterealtime.org/builds/smack/docs/latest/documentation/extensions/index.html[projects].
|
||||
And starting with Spring Integration _version 4.3_ any XEP can be use with the existing XMPP channel adapters.
|
||||
|
||||
To be able to process XEPs or any other custom XMPP extensions, the Smack's `ProviderManager` pre-configuration
|
||||
must be provided.
|
||||
It can be done via direct usage from the `static` Java code:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
ProviderManager.addIQProvider("element", "namespace", new MyIQProvider());
|
||||
ProviderManager.addExtensionProvider("element", "namespace", new MyExtProvider());
|
||||
----
|
||||
|
||||
or via `.providers` configuration file in the specific instance and JVM argument:
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
-Dsmack.provider.file=file:///c:/my/provider/mycustom.providers
|
||||
----
|
||||
|
||||
where `mycustom.providers` might be like this:
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<?xml version="1.0"?>
|
||||
<smackProviders>
|
||||
<iqProvider>
|
||||
<elementName>query</elementName>
|
||||
<namespace>jabber:iq:time</namespace>
|
||||
<className>org.jivesoftware.smack.packet.Time</className>
|
||||
</iqProvider>
|
||||
|
||||
<iqProvider>
|
||||
<elementName>query</elementName>
|
||||
<namespace>http://jabber.org/protocol/disco#items</namespace>
|
||||
<className>org.jivesoftware.smackx.provider.DiscoverItemsProvider</className>
|
||||
</iqProvider>
|
||||
|
||||
<extensionProvider>
|
||||
<elementName>subscription</elementName>
|
||||
<namespace>http://jabber.org/protocol/pubsub</namespace>
|
||||
<className>org.jivesoftware.smackx.pubsub.provider.SubscriptionProvider</className>
|
||||
</extensionProvider>
|
||||
</smackProviders>
|
||||
----
|
||||
|
||||
For example the most popular XMPP messaging extension is
|
||||
https://developers.google.com/cloud-messaging/[Google Cloud Messaging] (GCM).
|
||||
The Smack provides the particular `org.jivesoftware.smackx.gcm.provider.GcmExtensionProvider` for that and
|
||||
registers that by default with the `smack-experimental` jar in the classpath using `experimental.providers` resource:
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<!-- GCM JSON payload -->
|
||||
<extensionProvider>
|
||||
<elementName>gcm</elementName>
|
||||
<namespace>google:mobile:data</namespace>
|
||||
<className>org.jivesoftware.smackx.gcm.provider.GcmExtensionProvider</className>
|
||||
</extensionProvider>
|
||||
----
|
||||
|
||||
Also the `GcmPacketExtension` is present for the target messaging protocol to parse incoming packets and build outgoing:
|
||||
[source,java]
|
||||
----
|
||||
GcmPacketExtension gcmExtension = (GcmPacketExtension) xmppMessage.getExtension(GcmPacketExtension.NAMESPACE);
|
||||
String message = gcmExtension.getJson());
|
||||
----
|
||||
|
||||
[source,java]
|
||||
----
|
||||
GcmPacketExtension packetExtension = new GcmPacketExtension(gcmJson);
|
||||
Message smackMessage = new Message();
|
||||
smackMessage.addExtension(packetExtension);
|
||||
----
|
||||
|
||||
See <<xmpp-message-inbound-channel-adapter>> and <<xmpp-message-outbound-channel-adapter>> above for more information.
|
||||
|
||||
Reference in New Issue
Block a user