XMPP サポート
Spring Integration は、XMPP (英語) のチャネルアダプターを提供します。XMPP は "Extensible Messaging and Presence Protocol" の略です。
XMPP は、複数のエージェントが分散システムで互いに通信する方法を説明しています。XMPP は他の種類のアプリケーションに使用できます(また使用されています)が、標準的な使用例はチャットメッセージの送受信です。XMPP はアクターのネットワークを記述します。そのネットワーク内で、アクターは互いに直接対処し、ステータスの変化(「プレゼンス」など)をブロードキャストできます。
XMPP は、Google Talk (GTalk、GMail 内からも利用可能) や Facebook Chat など、世界最大のインスタントメッセージングネットワークの基盤となるメッセージングファブリックを提供します。多くの優れたオープンソース XMPP サーバーが利用可能です。一般的な実装としては、Openfire (英語) と ejabberd (英語) の 2 つがあります。
Spring の統合は、XMPP アダプターを提供することで XMPP をサポートします。XMPP アダプターは、XMPP チャットメッセージとクライアントの名簿の他のエントリからのプレゼンス変更の両方を送受信します。
この依存関係をプロジェクトに含める必要があります。
他のアダプターと同様に、XMPP アダプターは、便利な名前空間ベースの構成をサポートしています。XMPP 名前空間を構成するには、XML 構成ファイルのヘッダーに次の要素を含めます。
xmlns:int-xmpp="http://www.springframework.org/schema/integration/xmpp"
xsi:schemaLocation="http://www.springframework.org/schema/integration/xmpp
https://www.springframework.org/schema/integration/xmpp/spring-integration-xmpp.xsd"
XMPP 接続
受信または送信 XMPP アダプターを使用して XMPP ネットワークに参加する前に、アクターは XMPP 接続を確立する必要があります。特定のアカウントに接続されているすべての XMPP アダプターは、この接続オブジェクトを共有できます。通常、これには (最低でも) user
、password
、host
が必要です。基本的な XMPP 接続を作成するには、次の例に示すように、便利な名前空間を使用できます。
<int-xmpp:xmpp-connection
id="myConnection"
user="user"
password="password"
host="host"
port="port"
resource="theNameOfTheResource"
subscription-mode="accept_all"/>
利便性を高めるために、デフォルトの命名規則に依存して、id 属性を省略できます。この接続 Bean にはデフォルト名(xmppConnection )が使用されます。 |
XMPP 接続が古くなった場合、以前の接続状態がログに記録(認証)されている限り、自動ログインで再接続が試行されます。また、ConnectionListener
も登録します。ConnectionListener
は、DEBUG
ロギングレベルが有効になっている場合に接続イベントを記録します。
subscription-mode
属性は、他のユーザーからの受信サブスクリプションを処理するために名簿リスナーを開始します。この機能は、ターゲット XMPP サーバーで常に使用できるわけではありません。例: Google クラウドメッセージング (GCM) と Firebase クラウドメッセージング (FCM) は完全に無効にします。サブスクリプションの名簿リスナーをオフにするには、XML 構成 (subscription-mode=""
) を使用する場合は空の文字列を使用して、Java 構成を使用する場合は XmppConnectionFactoryBean.setSubscriptionMode(null)
を使用して構成できます。これを行うと、ログイン段階でも名簿が無効になります。詳細については、"Roster.setRosterLoadedAtLogin(boolean)
(英語) " を参照してください。
XMPP メッセージ
Spring Integration は、XMPP メッセージの送受信のサポートを提供します。受信するために、受信メッセージチャネルアダプターを提供します。送信するために、送信メッセージチャネルアダプターを提供します。
受信メッセージチャネルアダプター
Spring Integration アダプターは、システム内の他のユーザーからのチャットメッセージの受信をサポートしています。そのためには、受信メッセージチャネルアダプターがユーザーに代わってユーザーとして「ログイン」し、そのユーザーに送信されたメッセージを受信します。これらのメッセージは、Spring Integration クライアントに転送されます。inbound-channel-adapter
要素は、XMPP 受信メッセージチャネルアダプターの構成サポートを提供します。次の例は、構成方法を示しています。
<int-xmpp:inbound-channel-adapter id="xmppInboundAdapter"
channel="xmppInbound"
xmpp-connection="testConnection"
payload-expression="getExtension('google:mobile:data').json"
stanza-filter="stanzaFilter"
auto-startup="true"/>
通常の属性(メッセージチャネルアダプターの場合)に加えて、このアダプターには XMPP 接続への参照も必要です。
XMPP 受信アダプターはイベント駆動型で、Lifecycle
実装です。起動すると、受信 XMPP チャットメッセージをリッスンする PacketListener
を登録します。受信したメッセージはすべて基礎となるアダプターに転送され、アダプターは Spring Integration メッセージに変換して、指定された channel
に送信します。停止すると、PacketListener
の登録を解除します。
バージョン 4.3 以降、ChatMessageListeningEndpoint
(およびその <int-xmpp:inbound-channel-adapter>
)は、内部 StanzaListener
実装とともに、提供された XMPPConnection
に登録される org.jivesoftware.smack.filter.StanzaFilter
の挿入をサポートします。詳細については、Javadoc (英語) を参照してください。
バージョン 4.3 は、ChatMessageListeningEndpoint
に payload-expression
属性を導入しました。受信 org.jivesoftware.smack.packet.Message
は、評価コンテキストのルートオブジェクトを表します。このオプションは、XMPP 拡張を使用する場合に便利です。例: GCM プロトコルの場合、次の式を使用して本文を抽出できます。
payload-expression="getExtension('google:mobile:data').json"
次の例では、XHTML プロトコルの本文を抽出します。
payload-expression="getExtension(T(org.jivesoftware.smackx.xhtmlim.packet.XHTMLExtension).NAMESPACE).bodies[0]"
XMPP メッセージの拡張機能へのアクセスを簡素化するために、extension
変数が EvaluationContext
に追加されます。メッセージに拡張子が 1 つしかない場合に追加されることに注意してください。namespace
操作を示す前述の例は、次の例に簡略化できます。
payload-expression="#extension.json"
payload-expression="#extension.bodies[0]"
送信メッセージチャネルアダプター
送信メッセージチャネルアダプターを使用して、XMPP で他のユーザーにチャットメッセージを送信することもできます。outbound-channel-adapter
要素は、XMPP 送信メッセージチャネルアダプターの構成サポートを提供します。
<int-xmpp:outbound-channel-adapter id="outboundEventAdapter"
channel="outboundEventChannel"
xmpp-connection="testConnection"/>
アダプターは、その入力が(少なくとも)型 java.lang.String
のペイロードであり、どのユーザーにメッセージを送信するかを指定する XmppHeaders.CHAT_TO
のヘッダー値であると想定しています。メッセージを作成するには、次のような Java コードを使用できます。
Message<String> xmppOutboundMsg = MessageBuilder.withPayload("Hello, XMPP!" )
.setHeader(XmppHeaders.CHAT_TO, "userhandle")
.build();
次の例に示すように、XMPP ヘッダーエンリッチャーサポートを使用してヘッダーを設定することもできます。
<int-xmpp:header-enricher input-channel="input" output-channel="output">
<int-xmpp:chat-to value="[email protected] (英語) "/>
</int-xmpp:header-enricher>
バージョン 4.3 から、パケット拡張サポートが ChatMessageSendingMessageHandler
(XML 構成の <int-xmpp:outbound-channel-adapter>
) に追加されました。通常の String
および org.jivesoftware.smack.packet.Message
ペイロードに加えて、setBody()
の代わりに org.jivesoftware.smack.packet.XmlElement
( org.jivesoftware.smack.packet.Message.addExtension()
に入力される) のペイロードでメッセージを送信できるようになりました。便宜上、ChatMessageSendingMessageHandler
に extension-provider
オプションを追加しました。実行時にペイロードに対して XmlElement
を構築する org.jivesoftware.smack.provider.ExtensionElementProvider
を注入できます。この場合、XEP プロトコルに応じて、ペイロードは JSON または XML 形式の文字列である必要があります。
XMPP プレゼンス
XMPP は、ブロードキャスト状態もサポートします。この機能を使用して、名簿に載っている人にあなたの状態の変化を見ることができます。これは、IM クライアントで常に発生します。不在ステータスを変更して不在メッセージを設定すると、名簿に載っているすべての人が、この新しい状態を反映してアイコンまたはユーザー名が変更され、新しい「不在」メッセージが表示される場合があります。通知を受信したり、状態の変化を他の人に通知したい場合は、Spring Integration の「プレゼンス」アダプターを使用できます。
受信プレゼンスメッセージチャネルアダプター
Spring Integration は受信プレゼンスメッセージチャネルアダプターを提供します。これは、名簿に載っているシステム内の他のユーザーからのプレゼンスイベントの受信をサポートします。これを行うために、アダプターはユーザーに代わってユーザーとして「ログイン」し、RosterListener
を登録し、受信したプレゼンス更新イベントをメッセージとして channel
属性で識別されるチャネルに転送します。メッセージのペイロードは org.jivesoftware.smack.packet.Presence
オブジェクトです(www.igniterealtime.org/builds/smack/docs/latest/javadoc/org/jivesoftware/smack/packet/Presence.html (英語) を参照)。
presence-inbound-channel-adapter
要素は、XMPP 受信プレゼンスメッセージチャネルアダプターの構成サポートを提供します。次の例では、受信プレゼンスメッセージチャネルアダプターを構成します。
<int-xmpp:presence-inbound-channel-adapter channel="outChannel"
xmpp-connection="testConnection" auto-startup="false"/>
通常の属性に加えて、このアダプターには XMPP 接続への参照が必要です。このアダプターはイベント駆動型で、Lifecycle
実装です。起動時に RosterListener
を登録し、停止時に RosterListener
の登録を解除します。
発信プレゼンスメッセージチャネルアダプター
Spring Integration は、名簿に載っているネットワーク内の他のユーザーに表示されるプレゼンスイベントの送信もサポートしています。送信プレゼンスメッセージチャネルアダプターにメッセージを送信すると、ペイロード(型 org.jivesoftware.smack.packet.Presence
であると予想される)が抽出されて XMPP 接続に送信されるため、プレゼンスイベントがネットワークの残りの部分にアドバタイズされます。
presence-outbound-channel-adapter
要素は、XMPP 発信プレゼンスメッセージチャネルアダプターの構成サポートを提供します。次の例は、発信プレゼンスメッセージチャネルアダプターを構成する方法を示しています。
<int-xmpp:presence-outbound-channel-adapter id="eventOutboundPresenceChannel"
xmpp-connection="testConnection"/>
また、ポーリングコンシューマー(ポーリング可能なチャネルからメッセージを受信する場合)にすることもできます。この場合、ポーラーを登録する必要があります。次の例は、その方法を示しています。
<int-xmpp:presence-outbound-channel-adapter id="pollingOutboundPresenceAdapter"
xmpp-connection="testConnection"
channel="pollingChannel">
<int:poller fixed-rate="1000" max-messages-per-poll="1"/>
</int-xmpp:presence-outbound-channel-adapter>
受信版と同様に、XMPP 接続への参照が必要です。
XMPP 接続 Bean(前述)のデフォルトの命名規則に依存しており、アプリケーションコンテキストで構成されている XMPP 接続 Bean が 1 つしかない場合は、xmpp-connection 属性を省略できます。その場合、xmppConnection という名前の Bean が検出され、アダプターに挿入されます。 |
高度な構成
Spring Integration の XMPP サポートは、Smack 4.0 API(www.igniterealtime.org/projects/smack/ (英語) )に基づいており、XMPP 接続オブジェクトのより複雑な構成を可能にします。
前述のとおり、xmpp-connection
名前空間のサポートは、基本的な接続構成を簡素化するように設計されており、いくつかの一般的な構成属性のみをサポートします。ただし、org.jivesoftware.smack.ConnectionConfiguration
オブジェクトでは約 20 個の属性が定義されており、すべての名前空間のサポートを追加しても実際の価値はありません。より複雑な接続構成の場合、XmppConnectionFactoryBean
のインスタンスを通常の Bean として構成し、org.jivesoftware.smack.ConnectionConfiguration
をその FactoryBean
のコンストラクター引数として挿入できます。ConnectionConfiguration
インスタンスで必要なすべてのプロパティを直接指定できます。('p' 名前空間を持つ Bean 定義はうまく機能します)このように、SSL(または他の属性)を直接設定できます。次の例は、その方法を示しています。
<bean id="xmppConnection" class="o.s.i.xmpp.XmppConnectionFactoryBean">
<constructor-arg>
<bean class="org.jivesoftware.smack.ConnectionConfiguration">
<constructor-arg value="myServiceName"/>
<property name="socketFactory" ref="..."/>
</bean>
</constructor-arg>
</bean>
<int:channel id="outboundEventChannel"/>
<int-xmpp:outbound-channel-adapter id="outboundEventAdapter"
channel="outboundEventChannel"
xmpp-connection="xmppConnection"/>
Smack API には、役立つ静的初期化子も用意されています。より複雑なケース (SASL メカニズムの登録など) では、特定の静的初期化子を実行する必要がある場合があります。これらの静的初期化子の 1 つが SASLAuthentication
で、サポートされている SASL メカニズムを登録できます。そのレベルの複雑さについては、XMPP 接続構成に Spring Java 構成を使用することをお勧めします。そうすれば、Java コードを使用してコンポーネント全体を構成し、静的初期化子を含むその他すべての必要な Java コードを適切なタイミングで実行できます。次の例は、Java で SASL (Simple Authentication and Security Layer) を使用して XMPP 接続を構成する方法を示しています。
@Configuration
public class CustomConnectionConfiguration {
@Bean
public XMPPConnection xmppConnection() {
SASLAuthentication.supportSASLMechanism("EXTERNAL", 0); // static initializer
ConnectionConfiguration config = new ConnectionConfiguration("localhost", 5223);
config.setKeystorePath("path_to_truststore.jks");
config.setSecurityEnabled(true);
config.setSocketFactory(SSLSocketFactory.getDefault());
return new XMPPConnection(config);
}
}
アプリケーションコンテキストの構成に Java を使用する方法の詳細については、Spring リファレンスマニュアルの次のセクションを参照してください。
XMPP メッセージヘッダー
Spring Integration XMPP アダプターは、標準の XMPP プロパティを自動的にマッピングします。デフォルトでは、これらのプロパティは DefaultXmppHeaderMapper
(Javadoc) を使用して Spring Integration MessageHeaders
との間でコピーされます。
DefaultXmppHeaderMapper
の requestHeaderNames
または replyHeaderNames
プロパティで明示的に指定されていない限り、ユーザー定義のヘッダーは XMPP メッセージとの間でコピーされません。
ユーザー定義ヘッダーをマッピングする場合、値には単純なワイルドカードパターン( "thing *" または "* thing" など)を含めることもできます。 |
バージョン 4.1 以降、AbstractHeaderMapper
(DefaultXmppHeaderMapper
のスーパークラス)を使用すると、STANDARD_REQUEST_HEADERS
に加えて requestHeaderNames
プロパティの NON_STANDARD_HEADERS
トークンを構成して、すべてのユーザー定義ヘッダーをマッピングできます。
org.springframework.xmpp.XmppHeaders
クラスは、DefaultXmppHeaderMapper
によって使用されるデフォルトヘッダーを識別します。
xmpp_from
xmpp_subject
xmpp_thread
xmpp_to
xmpp_type
バージョン 4.3 以降では、パターンの前に !
を付けることにより、ヘッダーマッピングのパターンを無効にすることができます。否定パターンが優先されるため、STANDARD_REQUEST_HEADERS,thing1,thing*,!thing2,!thing3,qux,!thing1
などのリストは thing1
、thing2
、thing3
をマップしません。そのリストは、標準ヘッダーに加えて thing4
と qux
をマップします。
マッピングしたい ! で始まるユーザー定義ヘッダーがある場合は、\ でエスケープすることができます: STANDARD_REQUEST_HEADERS,\!myBangHeader 。その例では、標準のリクエストヘッダーと !myBangHeader がマッピングされます。 |
XMPP 拡張
拡張機能により、"Extensible Messaging and Presence Protocol" に "Extensible" が追加されました。
XMPP は、ネームスペースとして知られる概念をサポートするデータ形式である XML に基づいています。名前空間を通じて、元の仕様で定義されていないビットを XMPP に追加できます。XMPP 仕様では、コア機能のセットのみを意図的に説明しています。
クライアントがサーバーに接続する方法
暗号化 (SSL/TLS)
認証
サーバーが相互に通信してメッセージをリレーする方法
他のいくつかの基本的な構成要素
これを実装すると、XMPP クライアントが作成され、任意の種類のデータを送信できます。ただし、基本以上のことを行う必要がある場合があります。例: メッセージに書式設定(太字、斜体など)を含める必要がある場合がありますが、これはコア XMPP 仕様では定義されていません。まあ、それを行う方法を作ることができますが、他の人が同じようにしない限り、他のソフトウェアはそれを解釈できません(彼らは理解できない名前空間を無視します)。
この問題を解決するために、XMPP 標準 Foundation(XSF)は、XMPP 拡張プロトコル (英語) (XEP)として知られる一連の追加ドキュメントを公開しています。一般に、各 XEP は特定のアクティビティ(メッセージのフォーマットからファイル転送、マルチユーザーチャットなど)を記述します。また、すべての人がそのアクティビティに使用する標準形式を提供します。
Smack API は、extensions
および experimental
プロジェクト (英語) で多くの XEP 実装を提供します。Spring Integration バージョン 4.3 以降、既存の XMPP チャネルアダプターで任意の XEP を使用できます。
XEP または他のカスタム XMPP 拡張機能を処理できるようにするには、Smack の ProviderManager
事前設定を提供する必要があります。次の例に示すように、static
Java コードでこれを行うことができます。
ProviderManager.addIQProvider("element", "namespace", new MyIQProvider());
ProviderManager.addExtensionProvider("element", "namespace", new MyExtProvider());
次の例に示すように、特定のインスタンスで .providers
構成ファイルを使用し、JVM 引数でアクセスすることもできます。
-Dsmack.provider.file=file:///c:/my/provider/mycustom.providers
mycustom.providers
ファイルは次のようになります。
<?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>https://jabber.org/protocol/disco#items</namespace>
<className>org.jivesoftware.smackx.provider.DiscoverItemsProvider</className>
</iqProvider>
<extensionProvider>
<elementName>subscription</elementName>
<namespace>https://jabber.org/protocol/pubsub</namespace>
<className>org.jivesoftware.smackx.pubsub.provider.SubscriptionProvider</className>
</extensionProvider>
</smackProviders>
例: 最も一般的な XMPP メッセージング拡張機能は Google クラウドメッセージング (英語) (GCM)です。Smack ライブラリは、その目的のために org.jivesoftware.smackx.gcm.provider.GcmExtensionProvider
を提供します。デフォルトでは、次の Maven の例に示すように、experimental.providers
リソースを使用して、クラスパスの smack-experimental
jar にそのクラスを登録します。
<!-- GCM JSON payload -->
<extensionProvider>
<elementName>gcm</elementName>
<namespace>google:mobile:data</namespace>
<className>org.jivesoftware.smackx.gcm.provider.GcmExtensionProvider</className>
</extensionProvider>
また、GcmPacketExtension
では、次の例に示すように、ターゲットメッセージングプロトコルが受信パケットを解析し、発信パケットを構築できます。
GcmPacketExtension gcmExtension = (GcmPacketExtension) xmppMessage.getExtension(GcmPacketExtension.NAMESPACE);
String message = gcmExtension.getJson());
GcmPacketExtension packetExtension = new GcmPacketExtension(gcmJson);
Message smackMessage = new Message();
smackMessage.addExtension(packetExtension);
詳細については、この章で前述した受信メッセージチャネルアダプターおよび送信メッセージチャネルアダプターを参照してください。