INT-1222 moved the spring-integration-xmpp module from the sandbox to the trunk

This commit is contained in:
Mark Fisher
2010-07-05 15:41:37 +00:00
parent 00bca2d511
commit 8e8530b1fc
35 changed files with 2277 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
<classpathentry kind="src" output="target/classes" path="src/main/resources"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>spring-integration-xmpp</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.springframework.ide.eclipse.core.springbuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.maven.ide.eclipse.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.maven.ide.eclipse.maven2Nature</nature>
<nature>org.springframework.ide.eclipse.core.springnature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,3 @@
#Sun Jun 06 10:22:56 EDT 2010
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning

View File

@@ -0,0 +1,9 @@
#Sun Jun 06 10:20:24 EDT 2010
activeProfiles=
eclipse.preferences.version=1
fullBuildGoals=process-test-resources
includeModules=false
resolveWorkspaceProjects=true
resourceFilterGoals=process-resources resources\:testResources
skipCompilerPlugin=true
version=1

View File

@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-parent</artifactId>
<version>2.0.0.BUILD-SNAPSHOT</version>
</parent>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-xmpp</artifactId>
<packaging>jar</packaging>
<name>Spring Integration XMPP Support</name>
<dependencies>
<dependency>
<groupId>jivesoftware</groupId>
<artifactId>smack</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>jivesoftware</groupId>
<artifactId>smackx</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>${cglib.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>${org.easymock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymockclassextension</artifactId>
<version>${org.easymock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${org.springframework.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${org.springframework.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-stream</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-core</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.springsource.bundlor</groupId>
<artifactId>com.springsource.bundlor.maven</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,205 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.xmpp;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.SASLAuthentication;
import org.jivesoftware.smack.XMPPConnection;
import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.util.StringUtils;
/**
* This class configures an {@link org.jivesoftware.smack.XMPPConnection} object. This object is used for all scenarios to talk to a Smack server.
*
* @author Josh Long
* @author Mark Fisher
* @see {@link org.jivesoftware.smack.XMPPConnection}
* @since 2.0
*/
public class XmppConnectionFactory extends AbstractFactoryBean<XMPPConnection> {
// TODO provide a default subscription mode for this class: Roster.setSubscriptionMode(Roster.SubscriptionMode)
private static final Log logger = LogFactory.getLog(XmppConnectionFactory.class);
private volatile String user;
private volatile String password;
private volatile String host;
private volatile String serviceName;
private volatile String resource;
private volatile String saslMechanismSupported;
private volatile int saslMechanismSupportedIndex;
private volatile int port;
private volatile String subscriptionMode;
private volatile boolean debug = false;
public XmppConnectionFactory() {
}
public XmppConnectionFactory(String user, String password, String host, String serviceName, String resource, String saslMechanismSupported, int saslMechanismSupportedIndex, int port) {
this.user = user;
this.password = password;
this.host = host;
this.serviceName = serviceName;
this.resource = resource;
this.saslMechanismSupported = saslMechanismSupported;
this.saslMechanismSupportedIndex = saslMechanismSupportedIndex;
this.port = port;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public String getServiceName() {
return serviceName;
}
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
public String getResource() {
return resource;
}
public void setResource(String resource) {
this.resource = resource;
}
public String getSaslMechanismSupported() {
return saslMechanismSupported;
}
public void setSaslMechanismSupported(String saslMechanismSupported) {
this.saslMechanismSupported = saslMechanismSupported;
}
public int getSaslMechanismSupportedIndex() {
return saslMechanismSupportedIndex;
}
public void setSaslMechanismSupportedIndex(int saslMechanismSupportedIndex) {
this.saslMechanismSupportedIndex = saslMechanismSupportedIndex;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public boolean isDebug() {
return debug;
}
public void setDebug(boolean debug) {
XMPPConnection.DEBUG_ENABLED = debug;
this.debug = debug;
}
public void setSubscriptionMode(final String subscriptionMode) {
this.subscriptionMode = subscriptionMode;
}
@Override
public Class<?extends XMPPConnection> getObjectType() {
return XMPPConnection.class;
}
private XMPPConnection configureAndConnect(String usr, String pw, String host, int port, String serviceName, String resource, String saslMechanismSupported, int saslMechanismSupportedIndex) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("usr=%s, pw=%s, host=%s, port=%s, serviceName=%s, resource=%s, saslMechanismSupported=%s, saslMechanismSupportedIndex=%s", usr, pw, host, port, serviceName,
resource, saslMechanismSupported, saslMechanismSupportedIndex));
}
XMPPConnection.DEBUG_ENABLED = false; // default
ConnectionConfiguration connectionConfiguration = new ConnectionConfiguration(host, port, serviceName);
XMPPConnection connection = new XMPPConnection(connectionConfiguration);
try {
connection.connect();
// You have to put this code before you login
if (StringUtils.hasText(saslMechanismSupported)) {
SASLAuthentication.supportSASLMechanism(saslMechanismSupported, saslMechanismSupportedIndex);
}
// You have to specify the resoure (e.g. "@host.com") at the end
if (StringUtils.hasText(resource)) {
connection.login(usr, pw, resource);
} else {
connection.login(usr, pw);
}
if( StringUtils.hasText( this.subscriptionMode)) {
Roster.SubscriptionMode subscriptionMode = Roster.SubscriptionMode.valueOf( this.subscriptionMode) ;
connection.getRoster().setSubscriptionMode( subscriptionMode );
}
if (logger.isDebugEnabled()) {
logger.debug("authenticated? " + connection.isAuthenticated());
}
} catch (Exception e) {
logger.warn("failed to establish XMPP connnection", e);
}
return connection;
}
@Override
protected XMPPConnection createInstance() throws Exception {
return this.configureAndConnect(this.getUser(), this.getPassword(), this.getHost(), this.getPort(), this.getServiceName(), this.getResource(), this.getSaslMechanismSupported(),
this.getSaslMechanismSupportedIndex());
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.xmpp;
import org.springframework.integration.core.MessageHeaders;
/**
*
* Used as keys for {@link org.springframework.integration.core.Message} objects
* that handle XMPP events.
*
* @author Mario Gray
* @author Josh Long
* @since 2.0
*/
public class XmppHeaders {
private static final String PREFIX = MessageHeaders.PREFIX + "xmpp_";
public static final String CHAT = PREFIX + "chat_key";
public static final String CHAT_TO_USER = PREFIX + "chat_to_user";
public static final String CHAT_THREAD_ID = PREFIX + "thread_id";
public static final String TYPE = PREFIX + "type";
public static final String ROSTER_CHANGE_TYPE = PREFIX + "roster_change_type";
public static final String PRESENCE = PREFIX + "presence";
public static final String ROSTER = PREFIX + "roster";
public static final String PRESENCE_LANGUAGE = PRESENCE + "language" ;
public static final String PRESENCE_PRIORITY = PRESENCE + "priority" ;
public static final String PRESENCE_MODE = PRESENCE + "mode" ;
public static final String PRESENCE_TYPE = PRESENCE + "type" ;
public static final String PRESENCE_STATUS = PRESENCE + "status" ;
public static final String PRESENCE_FROM = PRESENCE+ "from";
}

View File

@@ -0,0 +1,176 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.xmpp.config;
import org.jivesoftware.smack.packet.Presence;
import org.springframework.integration.config.xml.HeaderEnricherParserSupport;
import org.springframework.integration.xmpp.XmppHeaders;
import org.w3c.dom.Element;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractOutboundChannelAdapterParser;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.util.StringUtils;
/**
* This class parses the schema for XMPP support.
*
* @author Josh Long
* @author Mark Fisher
* @since 2.0
*/
public class XmppNamespaceHandler extends NamespaceHandlerSupport {
private static final String PACKAGE_NAME = "org.springframework.integration.xmpp";
private static String[] attributes = new String[] {
"user", "password", "host", "service-name", "resource",
"sasl-mechanism-supported", "sasl-mechanism-supported-index", "port", "subscription-mode"
};
public void init() {
// connection
registerBeanDefinitionParser("xmpp-connection", new XmppConnectionParser());
// send/receive messages
registerBeanDefinitionParser("message-inbound-channel-adapter", new XmppMessageInboundEndpointParser());
registerBeanDefinitionParser("message-outbound-channel-adapter", new XmppMessageOutboundEndpointParser());
// presence
registerBeanDefinitionParser("roster-event-inbound-channel-adapter", new XmppRosterEventInboundEndpointParser());
registerBeanDefinitionParser("roster-event-outbound-channel-adapter", new XmppRosterEventOutboundEndpointParser());
registerBeanDefinitionParser("header-enricher", new XmppHeaderEnricherParser());
}
private static void configureXMPPConnection(Element element, BeanDefinitionBuilder builder, ParserContext parserContext) {
String ref = element.getAttribute("xmpp-connection");
if (StringUtils.hasText(ref)) {
builder.addPropertyReference("xmppConnection", ref);
}
else {
for (String attribute : attributes) {
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, attribute);
}
}
}
// connection management
private static class XmppConnectionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected String getBeanClassName(Element element) {
return PACKAGE_NAME + ".XmppConnectionFactory";
}
@Override
protected boolean shouldGenerateIdAsFallback() {
return true;
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
configureXMPPConnection(element, builder, parserContext);
}
}
// messages
private static class XmppMessageOutboundEndpointParser extends AbstractOutboundChannelAdapterParser {
@Override
protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
PACKAGE_NAME + ".messages.XmppMessageSendingMessageHandler");
configureXMPPConnection(element, builder, parserContext);
return builder.getBeanDefinition();
}
}
private static class XmppMessageInboundEndpointParser extends AbstractSingleBeanDefinitionParser {
@Override
protected String getBeanClassName(Element element) {
return PACKAGE_NAME + ".messages.XmppMessageDrivenEndpoint";
}
@Override
protected boolean shouldGenerateIdAsFallback() {
return true;
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
configureXMPPConnection(element, builder, parserContext);
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "channel", "requestChannel");
}
}
private static class XmppRosterEventOutboundEndpointParser extends AbstractOutboundChannelAdapterParser {
@Override
protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
PACKAGE_NAME + ".presence.XmppRosterEventMessageSendingHandler");
configureXMPPConnection(element, builder, parserContext);
return builder.getBeanDefinition();
}
}
private static class XmppRosterEventInboundEndpointParser extends AbstractSingleBeanDefinitionParser {
@Override
protected String getBeanClassName(Element element) {
return PACKAGE_NAME + ".presence.XmppRosterEventMessageDrivenEndpoint";
}
@Override
protected boolean shouldGenerateIdAsFallback() {
return true;
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
configureXMPPConnection(element, builder, parserContext);
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "channel", "requestChannel");
}
}
private static class XmppHeaderEnricherParser extends HeaderEnricherParserSupport {
public XmppHeaderEnricherParser() {
// chat headers
this.addElementToHeaderMapping("message-to", XmppHeaders.CHAT_TO_USER);
this.addElementToHeaderMapping("message-thread-id", XmppHeaders.CHAT_THREAD_ID);
// presence headers
this.addElementToHeaderMapping("presence-mode", XmppHeaders.PRESENCE_MODE, Presence.Mode.class);
this.addElementToHeaderMapping("presence-type" , XmppHeaders.PRESENCE_TYPE, Presence.Type.class );
this.addElementToHeaderMapping("presence-from", XmppHeaders.PRESENCE_FROM);
this.addElementToHeaderMapping("presence-status" , XmppHeaders.PRESENCE_STATUS);
this.addElementToHeaderMapping("presence-priority" , XmppHeaders.PRESENCE_PRIORITY, Integer.class);
}
}
}

View File

@@ -0,0 +1,144 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.xmpp.messages;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.springframework.context.Lifecycle;
import org.springframework.integration.channel.MessageChannelTemplate;
import org.springframework.integration.core.MessageChannel;
import org.springframework.integration.endpoint.AbstractEndpoint;
import org.springframework.integration.message.MessageBuilder;
import org.springframework.integration.xmpp.XmppHeaders;
/**
* This component logs in as a user and forwards any messages <em>to</em> that
* user on to downstream components. The component is an endpoint that has its
* own lifecycle and does not need any
* {@link org.springframework.integration.endpoint.AbstractPollingEndpoint.Poller}
* to work. It takes any message from a given XMPP session (as established by
* the current {@link org.jivesoftware.smack.XMPPConnection}) and forwards the
* {@link org.jivesoftware.smack.packet.Message} as the payload of the Spring
* Integration {@link org.springframework.integration.core.Message}. The
* {@link org.jivesoftware.smack.Chat} instance that's used is passed along as a
* header (under {@link org.springframework.integration.xmpp.XmppHeaders#CHAT}).
* Additionally, the {@link org.jivesoftware.smack.packet.Message.Type} is
* passed along under the header
* {@link org.springframework.integration.xmpp.XmppHeaders#TYPE}. Both of these
* pieces of metadata can be obtained directly from the payload, if required.
* They are here as a convenience.
* <p>
* <strong>Note</strong>: the {@link org.jivesoftware.smack.ChatManager}
* maintains a Map&lt;String, Chat&gt; for threads and users, where the threadID
* ({@link String}) is the key or the userID {@link String} is the key. This
* {@link java.util.Map} is a Smack-specific implementation called
* {@link org.jivesoftware.smack.util.collections.ReferenceMap} that removes
* key/values as references are dereferenced. Take care to enable this garbage
* collection, taking what you need from the payload and the headers and
* discarding as soon as possible.
*
* @author Josh Long
* @author Mark Fisher
* @see {@link org.jivesoftware.smack.ChatManager} the ChatManager class that
* keeps watch over all Chats between the client and any other
* participants.
* @see {@link org.springframework.integration.channel.MessageChannelTemplate}
* handles all interesing operations on any Spring Integration channels.
* @see {@link org.jivesoftware.smack.XMPPConnection} the XMPPConnection (as
* created by
* {@link org.springframework.integration.xmpp.XmppConnectionFactory}
*/
public class XmppMessageDrivenEndpoint extends AbstractEndpoint implements Lifecycle {
private static final Log logger = LogFactory.getLog(XmppMessageDrivenEndpoint.class);
private final MessageChannelTemplate channelTemplate = new MessageChannelTemplate();
private volatile MessageChannel requestChannel;
private volatile XMPPConnection xmppConnection;
private volatile boolean extractPayload = true;
/**
* This will be injected or configured via a <em>xmpp-connection-factory</em> element.
*
* @param xmppConnection
*/
public void setXmppConnection(final XMPPConnection xmppConnection) {
this.xmppConnection = xmppConnection;
}
/**
* @param requestChannel the channel on which the inbound message should be sent
*/
public void setRequestChannel(final MessageChannel requestChannel) {
this.channelTemplate.setDefaultChannel(requestChannel);
this.requestChannel = requestChannel;
}
/**
* Specify whether the text message body should be extracted when mapping to a
* Spring Integration Message payload. Otherwise, the full XMPP Message will be
* passed within the payload. This value is <em>true</em> by default.
*/
public void setExtractPayload(boolean extractPayload) {
this.extractPayload = extractPayload;
}
@Override
protected void doStart() {
logger.debug("start: " + xmppConnection.isConnected() + ":" + xmppConnection.isAuthenticated());
}
@Override
protected void doStop() {
if (xmppConnection.isConnected()) {
logger.debug("shutting down " + XmppMessageDrivenEndpoint.class.getName() + ".");
xmppConnection.disconnect();
}
}
@Override
protected void onInit() throws Exception {
channelTemplate.afterPropertiesSet();
xmppConnection.addPacketListener(new PacketListener() {
public void processPacket(final Packet packet) {
org.jivesoftware.smack.packet.Message message = (org.jivesoftware.smack.packet.Message) packet;
forwardXmppMessage(xmppConnection.getChatManager().getThreadChat(message.getThread()), message);
}
}, null);
}
private void forwardXmppMessage(Chat chat, Message xmppMessage) {
Object payload = (this.extractPayload ? xmppMessage.getBody() : xmppMessage);
MessageBuilder<?> messageBuilder = MessageBuilder.withPayload(payload)
.setHeader(XmppHeaders.TYPE, xmppMessage.getType())
.setHeader(XmppHeaders.CHAT, chat);
channelTemplate.send(messageBuilder.build(), requestChannel);
}
}

View File

@@ -0,0 +1,100 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.xmpp.messages;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.XMPPConnection;
import org.springframework.context.Lifecycle;
import org.springframework.integration.message.MessageHandler;
import org.springframework.integration.xmpp.XmppHeaders;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* @author Josh Long
* @author Mario Gray
* @since 2.0
*/
public class XmppMessageSendingMessageHandler implements MessageHandler, Lifecycle {
private static final Log logger = LogFactory.getLog(XmppMessageSendingMessageHandler.class);
private volatile boolean running;
private volatile XMPPConnection xmppConnection;
public void setXmppConnection(final XMPPConnection xmppConnection) {
this.xmppConnection = xmppConnection;
}
public void handleMessage(final org.springframework.integration.core.Message<?> message) {
try {
// pre-reqs: user to send, string to send as msg body
String messageBody = null;
String destinationUser = null;
Object payload = message.getPayload();
if (payload instanceof String) {
messageBody = (String) payload;
}
destinationUser = (String) message.getHeaders().get(XmppHeaders.CHAT_TO_USER);
Assert.state(StringUtils.hasText(destinationUser), "the destination user must not be null");
Assert.state(StringUtils.hasText(messageBody), "the message body must not be null");
String threadId = (String) message.getHeaders().get(XmppHeaders.CHAT_THREAD_ID);
Chat chat = getOrCreateChatWithParticipant(destinationUser, threadId);
if (chat != null) {
chat.sendMessage(messageBody);
}
}
catch (Exception e) {
logger.debug("failed to send XMPP message", e);
}
}
public boolean isRunning() {
return this.running;
}
public void start() {
this.running = true;
}
public void stop() {
this.running = false;
if (xmppConnection.isConnected()) {
if (logger.isInfoEnabled()) {
logger.info("shutting down XMPP connection");
}
xmppConnection.disconnect();
}
}
private Chat getOrCreateChatWithParticipant(String userId, String thread) {
Chat chat = null;
if (!StringUtils.hasText(thread)) {
chat = xmppConnection.getChatManager().createChat(userId, null);
}
else {
chat = xmppConnection.getChatManager().getThreadChat(thread);
if (chat == null) {
chat = xmppConnection.getChatManager().createChat(userId, thread, null);
}
}
return chat;
}
}

View File

@@ -0,0 +1,150 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.xmpp.presence;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jivesoftware.smack.packet.Presence;
import org.springframework.integration.core.Message;
import org.springframework.integration.core.MessageHeaders;
import org.springframework.integration.message.InboundMessageMapper;
import org.springframework.integration.message.MessageBuilder;
import org.springframework.integration.message.OutboundMessageMapper;
import org.springframework.integration.xmpp.XmppHeaders;
import org.springframework.util.StringUtils;
/**
* Implementation of the strategy interface {@link org.springframework.integration.message.OutboundMessageMapper}. This is the hook that lets the adapter receive various payloads from
* components inside Spring Integration and forward them correctly as {@link org.jivesoftware.smack.packet.Presence} instances.
*
* @author Josh Long
* @since 2.0
*/
public class XmppPresenceMessageMapper implements OutboundMessageMapper<Presence>,
InboundMessageMapper<Presence> {
private static final Log logger = LogFactory.getLog(XmppPresenceMessageMapper.class);
/**
* Returns a {@link org.springframework.integration.core.Message} with payload {@link org.jivesoftware.smack.packet.Presence}
*
* @param presence the presence object that can be used to present the priority, status, mode, and type of a given roster entry. This will be decomposed into a series of headers, as well as a payload
* @return the Message
* @throws Exception thrown if conversion should fail
*/
public Message<?> toMessage(Presence presence) throws Exception {
MessageBuilder<?> presenceMessageBuilder = MessageBuilder.withPayload(presence);
presenceMessageBuilder.setHeader(XmppHeaders.PRESENCE_PRIORITY, presence.getPriority());
presenceMessageBuilder.setHeader(XmppHeaders.PRESENCE_STATUS, presence.getStatus());
presenceMessageBuilder.setHeader(XmppHeaders.PRESENCE_MODE, presence.getMode());
presenceMessageBuilder.setHeader(XmppHeaders.PRESENCE_TYPE, presence.getType());
presenceMessageBuilder.setHeader(XmppHeaders.PRESENCE_FROM, presence.getFrom());
return presenceMessageBuilder.build();
}
/**
* Builds a {@link org.jivesoftware.smack.packet.Presence} object from the inbound Message headers, if possible.
*
* @param message the Message whose headers and payload willl b
* @return the presence object as constructed from the {@link org.springframework.integration.core.Message} object
* @throws Exception
*/
public Presence fromMessage(Message<?> message) throws Exception {
MessageHeaders messageHeaders = message.getHeaders();
Integer priority = (Integer) messageHeaders.get(XmppHeaders.PRESENCE_PRIORITY);
String status = (String) messageHeaders.get(XmppHeaders.PRESENCE_STATUS);
String language = (String) messageHeaders.get(XmppHeaders.PRESENCE_LANGUAGE);
String from = (String) messageHeaders.get(XmppHeaders.PRESENCE_FROM);
// trickery afoot
Object modeObj = messageHeaders.get(XmppHeaders.PRESENCE_MODE);
Presence.Mode mode = null;
Object typeObj = messageHeaders.get(XmppHeaders.PRESENCE_TYPE);
Presence.Type type = null;
if (typeObj instanceof String) {
try {
type = Presence.Type.valueOf((String) typeObj);
} catch (Throwable th) {
logger.debug("couldn't convert type header into an object of type Presence.Type");
}
} else if (modeObj instanceof Presence.Type) {
type = (Presence.Type) typeObj;
}
if (modeObj instanceof String) {
try {
mode = Presence.Mode.valueOf((String) modeObj);
} catch (Throwable th) {
logger.debug("couldn't convert mode header into an object of type Presence.Mode ");
}
} else if (modeObj instanceof Presence.Mode) {
mode = (Presence.Mode) modeObj;
}
Object payload = message.getPayload();
if (null != payload) {
if (payload instanceof Presence) {
return (Presence) payload;
}
if (payload instanceof Presence.Type) {
type = (Presence.Type) payload;
}
}
return this.factoryPresence(from, status, priority, type, mode, language);
}
private Presence factoryPresence(String from, String status, Integer priority,
Presence.Type type, Presence.Mode mode, String language) {
if (null == type) {
type = Presence.Type.available;
}
Presence presence = new Presence(type);
if (null != priority) {
presence.setPriority(priority);
}
if (StringUtils.hasText(status)) {
presence.setStatus(status);
}
if (StringUtils.hasText(from)) {
presence.setFrom(from);
}
if (null != mode) {
presence.setMode(mode);
}
if (StringUtils.hasText(language)) {
presence.setLanguage(language);
}
return presence;
}
}

View File

@@ -0,0 +1,134 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.xmpp.presence;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jivesoftware.smack.RosterListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.packet.Presence;
import org.springframework.context.Lifecycle;
import org.springframework.integration.channel.MessageChannelTemplate;
import org.springframework.integration.core.Message;
import org.springframework.integration.core.MessageChannel;
import org.springframework.integration.endpoint.AbstractEndpoint;
import org.springframework.integration.message.InboundMessageMapper;
import java.util.Collection;
/**
* Describes an endpoint that is able to login as usual with a {@link org.springframework.integration.xmpp.XmppConnectionFactory} and then emit {@link org.springframework.integration.core.Message}s when a particular event happens to the logged in users {@link org.jivesoftware.smack.Roster}. We try
* and generically propagate these events. In practical terms, there are a few events worth being notified of: <ul> <li>the {@link org.jivesoftware.smack.packet.Presence} of a user in the {@link org.jivesoftware.smack.Roster} has changed.</li> <li>the actual makeup of the logged-in user's {@link
* org.jivesoftware.smack.Roster} has changed: entries added, deleted, etc.</li> </ul>
*
* @author Josh Long
* @since 2.0
*/
public class XmppRosterEventMessageDrivenEndpoint extends AbstractEndpoint implements Lifecycle {
private static final Log logger = LogFactory.getLog(XmppRosterEventMessageDrivenEndpoint.class);
private volatile MessageChannel requestChannel;
private volatile XMPPConnection xmppConnection;
private InboundMessageMapper<Presence> messageMapper;
private final MessageChannelTemplate channelTemplate = new MessageChannelTemplate();
/**
* This will be injected or configured via a <em>xmpp-connection-factory</em> element.
*
* @param xmppConnection
*/
public void setXmppConnection(final XMPPConnection xmppConnection) {
this.xmppConnection = xmppConnection;
}
/**
* @param requestChannel the channel on which the inbound message should be sent
*/
public void setRequestChannel(final MessageChannel requestChannel) {
this.channelTemplate.setDefaultChannel(requestChannel);
this.requestChannel = requestChannel;
}
@Override
protected void doStart() {
logger.debug("start: " + xmppConnection.isConnected() + ":" +
xmppConnection.isAuthenticated());
}
@Override
protected void doStop() {
if (this.xmppConnection.isConnected()) {
logger.debug("shutting down " + XmppRosterEventMessageDrivenEndpoint.class.getName() +
".");
this.xmppConnection.disconnect();
}
}
@Override
protected void onInit() throws Exception {
if (null == this.messageMapper) {
this.messageMapper = new XmppPresenceMessageMapper();
}
this.channelTemplate.afterPropertiesSet();
this.xmppConnection.getRoster().addRosterListener(new EventForwardingRosterListener());
}
/**
* Called whenever an event happesn related to the {@link org.jivesoftware.smack.Roster}
*
* @param presence the {@link org.jivesoftware.smack.packet.Presence} object representing the new state (optional)
*/
protected void forwardRosterEventMessage(Presence presence) {
try {
Message<?> msg = this.messageMapper.toMessage(presence);
channelTemplate.send(msg, requestChannel);
} catch (Exception e) {
logger.error("Failed to map packet to message ", e);
}
}
public void setMessageMapper(InboundMessageMapper<Presence> messageMapper) {
this.messageMapper = messageMapper;
}
/**
* Subscribes to a given {@link org.jivesoftware.smack.Roster}s events and forwards them to components on the bus.
*/
class EventForwardingRosterListener implements RosterListener {
public void entriesAdded(final Collection<String> entries) {
logger.debug("entries added: " + StringUtils.join(entries.iterator(), ","));
}
public void entriesUpdated(final Collection<String> entries) {
logger.debug("entries updated: " + StringUtils.join(entries.iterator(), ","));
}
public void entriesDeleted(final Collection<String> entries) {
logger.debug("entries deleted: " + StringUtils.join(entries.iterator(), ","));
}
public void presenceChanged(final Presence presence) {
logger.debug("presence changed: " + ToStringBuilder.reflectionToString(presence));
forwardRosterEventMessage(presence);
}
}
}

View File

@@ -0,0 +1,74 @@
package org.springframework.integration.xmpp.presence;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.packet.Presence;
import org.springframework.context.Lifecycle;
import org.springframework.integration.core.Message;
import org.springframework.integration.message.*;
/**
* This class will facilitate publishing updated presence values for a given connection. This change happens on the {@link org.jivesoftware.smack.Roster#subscriptionMode} property.
*
* @author Josh Long
* @see {@link org.jivesoftware.smack.packet.Presence.Mode} the mode (i.e.: {@link org.jivesoftware.smack.packet.Presence.Mode#away})
* @see {@link org.jivesoftware.smack.packet.Presence.Type} the type (i.e.: {@link org.jivesoftware.smack.packet.Presence.Type#available} )
* @since 2.0
*/
public class XmppRosterEventMessageSendingHandler implements MessageHandler, Lifecycle {
private static final Log logger = LogFactory.getLog(XmppRosterEventMessageDrivenEndpoint.class);
private volatile boolean running;
private OutboundMessageMapper<Presence> messageMapper;
private volatile XMPPConnection xmppConnection;
public void setXmppConnection(final XMPPConnection xmppConnection) {
this.xmppConnection = xmppConnection;
}
public void handleMessage(final Message<?> message)
throws MessageRejectedException, MessageHandlingException, MessageDeliveryException {
try {
Presence presence = this.messageMapper.fromMessage(message);
this.xmppConnection.sendPacket(presence);
} catch (Exception e) {
logger.error("Failed to map packet to message ", e);
}
}
public boolean isRunning() {
return this.running;
}
public void start() {
if (null == this.messageMapper) {
this.messageMapper = new XmppPresenceMessageMapper();
}
this.running = true;
}
public void stop() {
this.running = false;
if (xmppConnection.isConnected()) {
if (logger.isInfoEnabled()) {
logger.info("shutting down XMPP connection");
}
xmppConnection.disconnect();
}
}
/**
* the MessageMapper is responsible for converting outbound Messages into status updates of type {@link org.jivesoftware.smack.packet.Presence}
* @param messageMapper
*/
public void setMessageMapper(OutboundMessageMapper<Presence> messageMapper) {
this.messageMapper = messageMapper;
}
}

View File

@@ -0,0 +1 @@
http\://www.springframework.org/schema/integration/xmpp=org.springframework.integration.xmpp.config.XmppNamespaceHandler

View File

@@ -0,0 +1,2 @@
http\://www.springframework.org/schema/integration/xmpp/spring-integration-xmpp-2.0.xsd=org/springframework/integration/xmpp/config/spring-integration-xmpp-2.0.xsd
http\://www.springframework.org/schema/integration/xmpp/spring-integration-xmpp.xsd=org/springframework/integration/xmpp/config/spring-integration-xmpp-2.0.xsd

View File

@@ -0,0 +1,259 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2010 the original author or authors
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<xsd:schema xmlns="http://www.springframework.org/schema/integration/xmpp"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:tool="http://www.springframework.org/schema/tool"
xmlns:integration="http://www.springframework.org/schema/integration"
targetNamespace="http://www.springframework.org/schema/integration/xmpp"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xsd:import namespace="http://www.springframework.org/schema/beans"/>
<xsd:import namespace="http://www.springframework.org/schema/tool"/>
<xsd:import namespace="http://www.springframework.org/schema/integration"
schemaLocation="http://www.springframework.org/schema/integration/spring-integration-2.0.xsd"/>
<xsd:element name="xmpp-connection">
<xsd:annotation>
<xsd:documentation>
Configures an XMPP connection that can in turn be referenced by other components
</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="id" type="xsd:string"/>
<xsd:attribute name="user" type="xsd:string" use="required"/>
<xsd:attribute name="password" type="xsd:string" use="required"/>
<xsd:attribute name="host" type="xsd:string" use="required"/>
<xsd:attribute name="service-name" type="xsd:string"/>
<xsd:attribute name="resource" type="xsd:string"/>
<xsd:attribute name="sasl-mechanism-supported" type="xsd:string"/>
<xsd:attribute name="sasl-mechanism-supported-index" type="xsd:string"/>
<xsd:attribute name="port" type="xsd:string" />
<xsd:attribute name="subscription-mode" default="accept_all" >
<xsd:annotation>
<xsd:documentation><![CDATA[
The subscription mode for the XMPP connection. Dictates the policy for handling inbound messages from entries not already on the roster.
Values can be "accept_all," "manual," or "reject_all."
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:NMTOKEN">
<xsd:enumeration value="accept_all"/>
<xsd:enumeration value="manual"/>
<xsd:enumeration value="reject_all"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name="roster-event-outbound-channel-adapter">
<xsd:annotation>
<xsd:documentation>
Configures an endpoint that will publish an updated {@link org.jivesoftware.smack.packet.Presence} state on your {@link XMPPConnection } object.
</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="id" type="xsd:string"/>
<xsd:attribute name="channel" use="required" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.core.MessageChannel"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="xmpp-connection" type="xsd:string" use="required" >
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.jivesoftware.smack.XMPPConnection"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name="roster-event-inbound-channel-adapter">
<xsd:annotation>
<xsd:documentation>
Configures an endpoint that will forward roster based events (entry managment and presence state changes) to components in the bus.
</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="id" type="xsd:string"/>
<xsd:attribute name="channel" use="required" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.core.MessageChannel"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="xmpp-connection" type="xsd:string" use="required" >
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.jivesoftware.smack.XMPPConnection"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name="message-inbound-channel-adapter">
<xsd:annotation>
<xsd:documentation>
Configures an endpoint that will receive messages sent to a given account and then forward those messages to components in the bus.
</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="id" type="xsd:string"/>
<xsd:attribute name="channel" use="required" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.core.MessageChannel"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="xmpp-connection" type="xsd:string" use="required" >
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.jivesoftware.smack.XMPPConnection"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name="message-outbound-channel-adapter">
<xsd:annotation>
<xsd:documentation>
Component that sends messages to an entry in the roster on behalf of components in the bus.
</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="id" type="xsd:string"/>
<xsd:attribute name="channel" use="required" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.core.MessageChannel"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="xmpp-connection" type="xsd:string" use="required" >
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.jivesoftware.smack.XMPPConnection"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name="header-enricher">
<xsd:complexType>
<xsd:annotation>
<xsd:documentation>
Defines a Transformer for adding XMPP headers.
</xsd:documentation>
</xsd:annotation>
<xsd:complexContent>
<xsd:extension base="transformerType">
<xsd:choice minOccurs="1" maxOccurs="unbounded">
<xsd:element name="message-to" type="headerType"/>
<xsd:element name="message-thread-id" type="headerType"/>
<xsd:element name="presence-from" type="headerType"/>
<xsd:element name="presence-mode" type="headerType"/>
<xsd:element name="presence-type" type="headerType"/>
<xsd:element name="presence-status" type="headerType"/>
<xsd:element name="presence-priority" type="headerType"/>
</xsd:choice>
<xsd:attribute name="default-overwrite">
<xsd:annotation>
<xsd:documentation>
Specify the default boolean value for whether to overwrite existing header values. This will only take effect for
sub-elements that do not provide their own 'overwrite' attribute. If the 'default-overwrite' attribute is not
provided, then the specified header values will NOT overwrite any existing ones with the same header names.
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="xsd:boolean xsd:string"/>
</xsd:simpleType>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="headerType">
<xsd:attribute name="value" type="xsd:string" />
<xsd:attribute name="ref" type="xsd:string" />
<xsd:attribute name="expression" type="xsd:string" />
<xsd:attribute name="overwrite">
<xsd:annotation>
<xsd:documentation>
Boolean value to indicate whether this header value should overwrite an existing header value for the same name.
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="xsd:boolean xsd:string"/>
</xsd:simpleType>
</xsd:attribute>
</xsd:complexType>
<xsd:complexType name="transformerType">
<xsd:attribute name="id" type="xsd:string"/>
<xsd:attribute name="input-channel" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.core.MessageChannel"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="output-channel" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.core.MessageChannel"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:schema>

View File

@@ -0,0 +1,62 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.xmpp.config;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.channel.MessageChannelTemplate;
import org.springframework.integration.core.Message;
import org.springframework.integration.message.*;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Mark Fisher
* @author Josh Long
* @since 2.0
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class XmppHeaderEnricherParserTests {
@Value("#{input}")
private DirectChannel input;
@Value("#{output}")
private DirectChannel output;
@Test
public void to() {
MessageChannelTemplate messageChannelTemplate = new MessageChannelTemplate();
output.subscribe(new MessageHandler() {
public void handleMessage(Message<?> message)
throws MessageRejectedException, MessageHandlingException,
MessageDeliveryException {
for (String h : message.getHeaders().keySet())
System.out.println(String.format("%s=%s (class: %s)", h, message.getHeaders().get(h), message.getHeaders().get(h).getClass().toString()));
}
});
messageChannelTemplate.send(MessageBuilder.withPayload("foo").build(), input);
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.xmpp.messages;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Mark Fisher
* @since 2.0
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class ConsoleChatTests {
@Test
public void run() throws Exception {
Thread.sleep( 10 * 1000 );
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.xmpp.messages;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Josh Long
* @since 2.0
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class InboundXmppEndpointTests {
@Test
public void run() throws Exception {
Thread.sleep( 10 * 1000 );
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.xmpp.messages;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* Testing support for sending messages.
*
* @author Josh Long
* @since 2.0
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class OutboundXmppEndpointTests {
@Test
public void run() throws Exception {
Thread.sleep(10 * 1000);
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.xmpp.messages;
import org.jivesoftware.smack.packet.Message;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.stereotype.Component;
/**
* Handle display of incoming XMPP messages to this user.
*
* @author Josh Long
* @author Mark Fisher
* @since 2.0
*/
@Component
public class XmppMessageConsumer {
@ServiceActivator
public void consume(Object input) throws Throwable {
String text = null;
if (input instanceof Message) {
text = ((Message) input).getBody();
}
else if (input instanceof String) {
text = (String) input;
}
else {
throw new IllegalArgumentException(
"expected either a Smack Message or a String, but received: " + input);
}
System.out.println("================================================================================");
System.out.println("message: " + text);
}
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.xmpp.messages;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.integration.core.Message;
import org.springframework.integration.message.MessageBuilder;
import org.springframework.integration.message.MessageSource;
import org.springframework.integration.xmpp.XmppHeaders;
import java.util.Date;
/**
* Generates XMPP messages every 2s and forwards them on a channel which in turn publishes the message through XMPP.
*
* @author Josh Long
* @since 2.0
*/
public class XmppMessageProducer implements MessageSource<String> {
private static final Log logger = LogFactory.getLog(XmppMessageProducer.class);
private volatile int counter;
private String recipient;
public void setRecipient(final String recipient) {
this.recipient = recipient;
}
public Message<String> receive() {
try {
if (counter > 10) {
logger.debug("return null");
return null;
}
counter += 1;
Thread.sleep(1000 * 2);
String msg = "the current time is " + new Date();
logger.info("sending message to recipient " + recipient);
return MessageBuilder.withPayload(msg).setHeader(XmppHeaders.CHAT_TO_USER, recipient).build();
}
catch (InterruptedException e) {
logger.debug("exception thrown when trying to receive a message", e);
}
return null;
}
}

View File

@@ -0,0 +1,24 @@
package org.springframework.integration.xmpp.presence;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* this class demonstrates that when I launch this and then manipulate the status of the
* user using Pidgin, the updated state is immediately delivered to the Spring Integration bus.
*
* @author Josh Long
* @since 2.0
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class InboundXmppRosterEventsEndpointTests {
@Test
public void run() throws Exception {
Thread.sleep( 60 * 1000);
}
}

View File

@@ -0,0 +1,23 @@
package org.springframework.integration.xmpp.presence;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
*
* Tests {@link XmppRosterEventMessageSendingHandler} to ensure that we are able to publish status.
*
*
* @author Josh Long
* @since 2.0
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class OutboundXmppRosterEventsEndpointTests {
@Test
public void testOutbound() throws Throwable {
Thread.sleep( 60 * 1000);
}
}

View File

@@ -0,0 +1,28 @@
package org.springframework.integration.xmpp.presence;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
*
* This class will demonstrate using both inbound adapter types in a 1-2 punch of:
* <UL>
* <LI> notifying the bus of a user's sudden online availability using &lt;xmpp:roster-event-inbound-channel-adapter&gt;</LI>
* <LI> sending that user a message using the &lt;xmpp:outbound-message-channel-adapter /&gt;</LI>
* </UL>
*
* @author Josh Long
* @since 2.0
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class PresenceMessageComboTests {
@Test
public void run () throws Throwable {
Thread.sleep( 60 * 1000);
}
}

View File

@@ -0,0 +1,29 @@
package org.springframework.integration.xmpp.presence;
import org.apache.commons.lang.StringUtils;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.core.Message;
import org.springframework.integration.core.MessageHeaders;
import org.springframework.integration.xmpp.XmppHeaders;
import java.util.Collection;
/**
*
* This class reacts to changes in {@link org.jivesoftware.smack.packet.Presence} objects for a given account.
*
* @author Josh Long
* @since 2.0
*/
public class XmppRosterEventConsumer {
@ServiceActivator
public void presenceChanged ( Message<?> presenceEventMsg ) throws Exception {
System.out.println(StringUtils.repeat( "-" , 100));
String whosePresence = (String)presenceEventMsg.getHeaders().get( XmppHeaders.PRESENCE_FROM);
System.out.println( "entries affected: " + whosePresence);
MessageHeaders messageHeaders = presenceEventMsg.getHeaders();
for( String h : messageHeaders.keySet() )
System.out.println( String.format( "%s = %s", h, messageHeaders.get(h)));
}
}

View File

@@ -0,0 +1,31 @@
package org.springframework.integration.xmpp.presence;
import org.apache.commons.lang.StringUtils;
import org.jivesoftware.smack.packet.Presence;
import org.springframework.integration.core.Message;
import org.springframework.integration.message.*;
import org.springframework.integration.xmpp.XmppHeaders;
/**
* This is used in {@link org.springframework.integration.xmpp.presence.OutboundXmppRosterEventsEndpointTests} to produce fake status / presence updates.
*
* @author Josh Long
* @since 2.0
*/
public class XmppRosterEventProducer implements MessageSource<String> {
public Message<String> receive() {
try {
Thread.sleep(1000 * 10);
} catch (InterruptedException e) {
// eat it
}
return (Math.random() > .5) ?
MessageBuilder.withPayload(StringUtils.EMPTY).setHeader(XmppHeaders.PRESENCE_MODE, Presence.Mode.chat).setHeader(XmppHeaders.PRESENCE_TYPE, Presence.Type.available)
.setHeader(XmppHeaders.PRESENCE_STATUS, "She Loves me").build() :
MessageBuilder.withPayload(StringUtils.EMPTY).setHeader(XmppHeaders.PRESENCE_MODE, Presence.Mode.dnd).setHeader(XmppHeaders.PRESENCE_TYPE, Presence.Type.available)
.setHeader(XmppHeaders.PRESENCE_STATUS, "She Loves me not").build();
}
}

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2010 the original author or authors
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<beans:beans
xmlns="http://www.springframework.org/schema/integration"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/beans/spring-context.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd">
<channel id="input"/>
<channel id="output"/>
<xmpp:header-enricher input-channel="input" output-channel="output">
<xmpp:presence-from value="test@example.org"/>
<xmpp:presence-mode value="available"/>
<xmpp:message-to value="test1@example.org"/>
<xmpp:presence-type value="unavailable"/>
</xmpp:header-enricher>
</beans:beans>

View File

@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2010 the original author or authors ~ ~ Licensed under the
Apache License, Version 2.0 (the "License"); ~ you may not use this
file except in compliance with the License. ~ You may obtain a copy of
the License at ~ ~ http://www.apache.org/licenses/LICENSE-2.0 ~ ~
Unless required by applicable law or agreed to in writing, software ~
distributed under the License is distributed on an "AS IS" BASIS, ~
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. ~ See the License for the specific language governing
permissions and ~ limitations under the License.
-->
<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"
xmlns:console="http://www.springframework.org/schema/integration/stream"
xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
http://www.springframework.org/schema/tool http://www.springframework.org/schema/tool/spring-tool-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration/xmpp http://www.springframework.org/schema/integration/xmpp/spring-integration-xmpp.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.0.xsd
http://www.springframework.org/schema/integration/stream http://www.springframework.org/schema/integration/stream/spring-integration-stream.xsd">
<beans:bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" p:ignoreUnresolvablePlaceholders="false">
<beans:property name="location">
<beans:bean class="org.springframework.core.io.FileSystemResource">
<beans:constructor-arg value="#{ systemProperties['user.home'] }/Desktop/test.properties"/>
</beans:bean>
</beans:property>
</beans:bean>
<xmpp:xmpp-connection
id="testConnection"
user="${user.2.login}"
password="${user.2.password}"
host="${user.2.host}"
port="${user.2.port}"
resource="${user.2.resource}"
sasl-mechanism-supported="${user.2.sasl.mechanism}"
sasl-mechanism-supported-index="${user.2.sasl.index}"
service-name="${user.2.service}"
/>
<console:stdout-channel-adapter id="stdout" append-newline="true"/>
<console:stdin-channel-adapter id="stdin"/>
<header-enricher input-channel="stdin" output-channel="messagesToSend">
<header name="#{T(org.springframework.integration.xmpp.XmppHeaders).CHAT_TO_USER}" value="${user.1.login}"/>
</header-enricher>
<xmpp:message-inbound-channel-adapter channel="stdout" xmpp-connection="testConnection"/>
<channel id="messagesToSend"/>
<xmpp:message-outbound-channel-adapter channel="messagesToSend" xmpp-connection="testConnection"/>
<poller default="true">
<interval-trigger interval="1" time-unit="SECONDS" />
</poller>
</beans:beans>

View File

@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2010 the original author or authors
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<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
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/tool http://www.springframework.org/schema/tool/spring-tool-3.0.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.0.xsd">
<context:component-scan base-package="org.springframework.integration.xmpp"/>
<beans:bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" p:ignoreUnresolvablePlaceholders="false">
<beans:property name="location">
<beans:bean class="org.springframework.core.io.FileSystemResource">
<beans:constructor-arg value="#{ systemProperties['user.home'] }/Desktop/test.properties"/>
</beans:bean>
</beans:property>
</beans:bean>
<channel id="xmppInbound"/>
<xmpp:xmpp-connection
id="testConnection"
user="${user.2.login}"
password="${user.2.password}"
host="${user.2.host}"
port="${user.2.port}"
resource="${user.2.resource}"
sasl-mechanism-supported="${user.2.sasl.mechanism}"
sasl-mechanism-supported-index="${user.2.sasl.index}"
service-name="${user.2.service}"
/>
<xmpp:message-inbound-channel-adapter channel="xmppInbound" xmpp-connection="testConnection"/>
<service-activator input-channel="xmppInbound" ref="xmppMessageConsumer"/>
</beans:beans>

View File

@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2010 the original author or authors ~ ~ Licensed under the
Apache License, Version 2.0 (the "License"); ~ you may not use this
file except in compliance with the License. ~ You may obtain a copy of
the License at ~ ~ http://www.apache.org/licenses/LICENSE-2.0 ~ ~
Unless required by applicable law or agreed to in writing, software ~
distributed under the License is distributed on an "AS IS" BASIS, ~
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. ~ See the License for the specific language governing
permissions and ~ limitations under the License.
-->
<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
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/tool http://www.springframework.org/schema/tool/spring-tool-3.0.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.0.xsd">
<context:component-scan base-package="org.springframework.integration.xmpp"/>
<beans:bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" p:ignoreUnresolvablePlaceholders="false">
<beans:property name="location">
<beans:bean class="org.springframework.core.io.FileSystemResource">
<beans:constructor-arg value="#{ systemProperties['user.home'] }/Desktop/test.properties"/>
</beans:bean>
</beans:property>
</beans:bean>
<beans:bean id="xmppProducer" class="org.springframework.integration.xmpp.messages.XmppMessageProducer" p:recipient="${user.2.login}"/>
<poller default="true">
<interval-trigger fixed-rate="true" interval="10" time-unit="SECONDS"/>
</poller>
<xmpp:xmpp-connection
id="testConnection"
user="${user.1.login}"
password="${user.1.password}"
host="${user.1.host}"
port="${user.1.port}"
resource="${user.1.resource}"
sasl-mechanism-supported="${user.1.sasl.mechanism}"
sasl-mechanism-supported-index="${user.1.sasl.index}"
service-name="${user.1.service}"
/>
<inbound-channel-adapter ref="xmppProducer" channel="outboundChannel"/>
<channel id="outboundChannel"/>
<xmpp:message-outbound-channel-adapter channel="outboundChannel" xmpp-connection="testConnection"/>
</beans:beans>

View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2010 the original author or authors ~ ~ Licensed under the
Apache License, Version 2.0 (the "License"); ~ you may not use this
file except in compliance with the License. ~ You may obtain a copy of
the License at ~ ~ http://www.apache.org/licenses/LICENSE-2.0 ~ ~
Unless required by applicable law or agreed to in writing, software ~
distributed under the License is distributed on an "AS IS" BASIS, ~
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. ~ See the License for the specific language governing
permissions and ~ limitations under the License.
-->
<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"
xmlns:console="http://www.springframework.org/schema/integration/stream"
xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
http://www.springframework.org/schema/tool http://www.springframework.org/schema/tool/spring-tool-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration/xmpp http://www.springframework.org/schema/integration/xmpp/spring-integration-xmpp.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.0.xsd
http://www.springframework.org/schema/integration/stream http://www.springframework.org/schema/integration/stream/spring-integration-stream.xsd">
<beans:bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" p:ignoreUnresolvablePlaceholders="false">
<beans:property name="location">
<beans:bean class="org.springframework.core.io.FileSystemResource">
<beans:constructor-arg value="#{ systemProperties['user.home'] }/Desktop/test.properties"/>
</beans:bean>
</beans:property>
</beans:bean>
<beans:bean id="xmppRosterEventConsumer" class="org.springframework.integration.xmpp.presence.XmppRosterEventConsumer" />
<xmpp:xmpp-connection
id="testConnection"
user="${user.1.login}"
password="${user.1.password}"
host="${user.1.host}"
port="${user.1.port}"
resource="${user.1.resource}"
sasl-mechanism-supported="${user.1.sasl.mechanism}"
sasl-mechanism-supported-index="${user.1.sasl.index}"
service-name="${user.1.service}"
/>
<channel id="inboundRosterEventChannel"/>
<xmpp:roster-event-inbound-channel-adapter channel="inboundRosterEventChannel" xmpp-connection="testConnection"/>
<service-activator input-channel="inboundRosterEventChannel" ref="xmppRosterEventConsumer"/>
</beans:beans>

View File

@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2010 the original author or authors ~ ~ Licensed under the
Apache License, Version 2.0 (the "License"); ~ you may not use this
file except in compliance with the License. ~ You may obtain a copy of
the License at ~ ~ http://www.apache.org/licenses/LICENSE-2.0 ~ ~
Unless required by applicable law or agreed to in writing, software ~
distributed under the License is distributed on an "AS IS" BASIS, ~
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. ~ See the License for the specific language governing
permissions and ~ limitations under the License.
-->
<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"
xmlns:console="http://www.springframework.org/schema/integration/stream"
xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
http://www.springframework.org/schema/tool http://www.springframework.org/schema/tool/spring-tool-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration/xmpp http://www.springframework.org/schema/integration/xmpp/spring-integration-xmpp.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.0.xsd
http://www.springframework.org/schema/integration/stream http://www.springframework.org/schema/integration/stream/spring-integration-stream.xsd">
<beans:bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" p:ignoreUnresolvablePlaceholders="false">
<beans:property name="location">
<beans:bean class="org.springframework.core.io.FileSystemResource">
<beans:constructor-arg value="#{ systemProperties['user.home'] }/Desktop/test.properties"/>
</beans:bean>
</beans:property>
</beans:bean>
<xmpp:xmpp-connection
id="testConnection"
user="${user.1.login}"
password="${user.1.password}"
host="${user.1.host}"
port="${user.1.port}"
resource="${user.1.resource}"
sasl-mechanism-supported="${user.1.sasl.mechanism}"
sasl-mechanism-supported-index="${user.1.sasl.index}"
service-name="${user.1.service}"
/>
<beans:bean id="eventProducer" class="org.springframework.integration.xmpp.presence.XmppRosterEventProducer" />
<inbound-channel-adapter ref="eventProducer" channel="rosterPresenceUpdatingProducerChannel">
<poller>
<interval-trigger interval="10000" />
</poller>
</inbound-channel-adapter>
<channel id="rosterPresenceUpdatingProducerChannel"/>
<xmpp:roster-event-outbound-channel-adapter xmpp-connection="testConnection" channel="rosterPresenceUpdatingProducerChannel"/>
</beans:beans>

View File

@@ -0,0 +1,32 @@
#
# Copyright 2010 the original author or authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# to be able to run these tests, put this file on your desktop and configure as appropriate
user.1.login=user1@gmail.com
user.1.password=password
user.1.host=talk.google.com
user.1.service=gmail.com
user.1.sasl.mechanism=PLAIN
user.1.sasl.index=0
user.1.resource=resource
user.1.port=5222
user.2.login=user2@gmail.com
user.2.password=password
user.2.host=talk.google.com
user.2.service=gmail.com
user.2.sasl.mechanism=PLAIN
user.2.sasl.index=0
user.2.resource=resource
user.2.port=5222

View File

@@ -0,0 +1,15 @@
Bundle-SymbolicName: org.springframework.integration.xmpp
Bundle-Name: Spring Integration XMPP Support
Bundle-Vendor: SpringSource
Bundle-ManifestVersion: 2
Import-Template:
org.apache.commons.logging;version="[1.1.1, 2.0.0)",
org.apache.commons.lang.*;version="[2.5.0, 3.0.0)",
org.springframework.integration.*;version="[2.0.0, 2.0.1)",
org.springframework.beans.*;version="[3.0.0, 4.0.0)",
org.springframework.context;version="[3.0.0, 4.0.0)",
org.springframework.core.*;version="[3.0.0, 4.0.0)",
org.springframework.util;version="[3.0.0, 4.0.0)",
org.jivesoftware.*;version="[3.1.0, 4.0.0)",
javax.*;version="0",
org.w3c.dom.*;version="0"