CHAPTER 13

images

Social Messaging

Social computing is taking the Internet by storm. With the rising popularity of e-mail, Instant Messaging (IM), Facebook, and Twitter, social computing has become mainstream. Social computing technologies use a large part of the current Internet bandwidth and are continuing to grow.

Part of the appeal of these technologies is that they help connect applications with real users. They enable a whole realm of applications to become part of the users’ world and workflow. Applications that ingratiate themselves with their users by becoming a natural extension of the tools and workflows with which the world is already familiar will be used more than similar tools that are less intuitive. Some of these technologies, like chat and news streams, trade on the data most interesting to a most people: their own. These technologies, which foster active interest from their users, encourage them to invest in it. In a sense, an application that succeeds in making itself relevant to its user base will grow on the strength of its community, not just on the efforts of a marketing team.

Spring Integration social messaging adapters are different from many of the other adapters discussed in this book because these are all about bringing an application’s data and services to an external user, not necessarily another system. Spring Integration currently supports integrating with e-mail, XMPP (Jabber, GTalk, Facebook Chat), news feeds (RSS, ATOM), and Twitter. The Spring Integration adapter supporting these protocols will be discussed in this chapter.

E-mail

Spring Integration supports the usual e-mail protocol, allowing the sending of e-mail based on incoming channel messages and the receiving of e-mails as channel messages. IMAP, IMAP-IDLE, POP3, and SMTP examples are discussed in the following sections. First, the required Maven dependencies must be added to support the Spring Integration e-mail adapters. The dependencies are shown in Listing 13–1.

Listing 13–1. Maven Dependencies for E-mail Support

    <dependency>
      <groupId>org.springframework.integration</groupId>
      <artifactId>spring-integration-mail</artifactId>
      <version>2.0.1.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>javax.activation</groupId>
      <artifactId>activation</artifactId>
      <version>1.1.1</version>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>javax.mail</groupId>
      <artifactId>mail</artifactId>
      <version>1.4.1</version>
    </dependency>

IMAP and IMAP-IDLE

Spring Integration supports IMAP and IMAP-IDLE for incoming e-mails. IMAP-IDLE allows for asynchronous (push) reception of e-mail if the e-mail server supports it. The standard IMAP adapter requires polling to pull the e-mails from the server.

The Spring configuration for an IMAP polling channel adapter is shown in Listing 13–2. The Spring Integration mail namespace has been added, as well as the Spring utility namespace to support configuring the Java mail properties. The mail inbound channel adapter support both the IMAP and POP3 mail protocol. For this example, the inbound adapter is configured for Gmail receiving the e-mail using IMAP protocol. The POP3 protocol configuration will be shown in the next section. Use the store-uri attribute to configure the protocol, host, port, and username/password if required. The poller element has been added to check for e-mail every five seconds, downloading one e-mail with each poll. The e-mail message is sent to the inputMail channel. The mail-to-spring transformer is used to convert the incoming mail payload into a string representation. The two attribute options worth mentioning are should-delete-messages, which removes the message from the server after downloading, and should-mark-messages-as-read, which marks the message on the server so it is only downloaded once. Note that the latter attribute is only supported for IMAP, not for POP3. Thus the should-delete-messages is the only way to prevent multiple downloads of the e-mail message if the adapter is restarted for the POP3 protocol. This will be discussed in more detail in the POP3 section.

Listing 13–2. Receiving E-mail with IMAP Spring Configuration imap-mail.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:int="http://www.springframework.org/schema/integration"
       xmlns:mail="http://www.springframework.org/schema/integration/mail"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/integration
    http://www.springframework.org/schema/integration/spring-integration-2.0.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/integration/mail
    http://www.springframework.org/schema/integration/mail/spring-integration-mail-2.0.xsd
    http://www.springframework.org/schema/util
    http://www.springframework.org/schema/util/spring-util-3.0.xsd">

  <int:channel id="inputChannel"/>

  <int:channel id="inputMail"/>

  <mail:mail-to-string-transformer input-channel="inputMail" output-channel="inputChannel"/>

  <mail:inbound-channel-adapter id="customAdapter"
                                store-uri=
                                    "imaps://[usename]:[password]@imap.gmail.com:993/inbox"
                                channel="inputMail"
                                should-delete-messages="false"
                                should-mark-messages-as-read="false"
                                java-mail-properties="javaMailProperties">
    <int:poller max-messages-per-poll="1" fixed-rate="5000"/>
  </mail:inbound-channel-adapter>

  <util:properties id="javaMailProperties">
    <prop key="mail.imap.socketFactory.class">javax.net.ssl.SSLSocketFactory</prop>
    <prop key="mail.imap.socketFactory.fallback">false</prop>
    <prop key="mail.store.protocol">imaps</prop>
    <prop key="mail.debug">false</prop>
  </util:properties>

</beans>

Note that the Spring util namespace is used to populate the java mail properties required by the mail adapter with parameters needed to support SSL security. This example is using Gmail IMAP support.

In order to the test the inbound e-mail adapters, a simple main class is required, as shown in Listing 13–3. This test class loads the Spring configuration file and subscribes to the inputChannel message channel. The message handler will log any new e-mail message.

Listing 13–3. IMAP E-mail Receiving main Class ImapMail

package com.apress.prospringintegration.social.mail;

import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.Message;
import org.springframework.integration.MessagingException;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.core.MessageHandler;

public class ImapMail {
    private static Logger LOG = Logger.getLogger(ImapMail.class);

    public static void main(String[] args) throws Exception {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("/spring/mail/imap-mail.xml");

        DirectChannel inputChannel = context.getBean("inputChannel", DirectChannel.class);

        inputChannel.subscribe(new MessageHandler() {
            public void handleMessage(Message<?> message) throws MessagingException {
                LOG.info("Message: " + message);
            }
        });
    }
}

If the e-mail server supports IMAP idle, the imap-idle-channel-adapter may be used to support event-driven notifications. This adapter will send the e-mail message to the specified channel any time a notification is received. This eliminates the need for a poller element. Except for the missing poller element and using the imap-idle-channel-adapter, the configuration is identical to the standard IMAP adapter. An example of the Spring configuration for this adapter, specifically for a Gmail e-mail server, is shown in Listing 13–4.

Listing 13–4. Receiving E-mail with IMAP-IDLE Spring Configuration imap-idle-mail.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:int="http://www.springframework.org/schema/integration"
       xmlns:mail="http://www.springframework.org/schema/integration/mail"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/integration
    http://www.springframework.org/schema/integration/spring-integration-2.0.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/integration/mail
    http://www.springframework.org/schema/integration/mail/spring-integration-mail-2.0.xsd
    http://www.springframework.org/schema/util
    http://www.springframework.org/schema/util/spring-util-3.0.xsd">

  <int:channel id="inputChannel"/>

  <int:channel id="inputMail"/>

  <mail:mail-to-string-transformer input-channel="inputMail" output-channel="inputChannel"/>

  <mail:imap-idle-channel-adapter id="customAdapter"
                                  store-uri=
                                      "imaps://[username]:[password]@imap.gmail.com:993/inbox"
                                  channel="inputMail"
                                  should-delete-messages="false"
                                  should-mark-messages-as-read="false"
                                  java-mail-properties="javaMailProperties"/>

  <util:properties id="javaMailProperties">
    <prop key="mail.imap.socketFactory.class">javax.net.ssl.SSLSocketFactory</prop>
    <prop key="mail.imap.socketFactory.fallback">false</prop>
    <prop key="mail.store.protocol">imaps</prop>
    <prop key="mail.debug">false</prop>
  </util:properties>

</beans>

To test the IMAP-IDLE mail adapter, a simple main class is created, as shown in Listing 13–5. This class is similar to the previous IMAP example. A message handler is added to the inputChannel message channel and will log any new e-mail message on the server.

Listing 13–5. IMAP-IDLE mail receiving main class ImapIdle-mail

package com.apress.prospringintegration.social.mail;

import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.Message;
import org.springframework.integration.MessagingException;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.core.MessageHandler;

public class ImapIdle-mail {
    private static Logger LOG = Logger.getLogger(ImapMail.class);

    public static void main(String[] args) throws Exception {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("/spring/mail/imap-idle-mail.xml");

        DirectChannel inputChannel = context.getBean("inputChannel", DirectChannel.class);

        inputChannel.subscribe(new MessageHandler() {
            public void handleMessage(Message<?> message) throws MessagingException {
                LOG.info("Message: " + message);
            }
        });
    }
}

POP3

The inbound-channel-adapter also supports the POP3 e-mail protocol. The configuration is identical to the IMAP configuration except for the store-uri attribute. This attribute must be prefaced with pop3 as opposed to imaps. The most important difference between the POP3 adapter and IMAP is the lack of the should-mark-messages-as-read attribute. POP3 protocol has no concept of what messages have been read. POP3 only keeps track of which messages were downloaded on a per-session basis. If a new session has been started, all previously downloaded e-mails will be downloaded again. The only option is to delete the message on the server after downloading using the should-delete-messages attribute. This is one of the reasons this is a required attribute. However, if this attribute is set to true, any other client will be unable to access the downloaded messages. The setting of this attribute should be carefully selected. An example of the Spring configuration for POP3 protocol is shown in Listing 13–6.

Listing 13–6. Receiving e-mail with POP3 Spring configuration pop-mail.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:int="http://www.springframework.org/schema/integration"
       xmlns:mail="http://www.springframework.org/schema/integration/mail"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/integration
    http://www.springframework.org/schema/integration/spring-integration-2.0.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/integration/mail
    http://www.springframework.org/schema/integration/mail/spring-integration-mail-2.0.xsd
    http://www.springframework.org/schema/util
    http://www.springframework.org/schema/util/spring-util-3.0.xsd">

  <int:channel id="inputChannel"/>

  <int:channel id="inputMail"/>

  <mail:mail-to-string-transformer input-channel="inputMail" output-channel="inputChannel"/>

  <mail:inbound-channel-adapter id="customAdapter"
                                store-uri="pop3://[username]:[password]@pop.gmail.com/inbox"
                                channel="inputMail"
                                should-delete-messages="false"
                                java-mail-properties="javaMailProperties">
    <int:poller max-messages-per-poll="1" fixed-rate="5000"/>
  </mail:inbound-channel-adapter>

  <util:properties id="javaMailProperties">
    <prop key="mail.pop3.socketFactory.fallback">false</prop>
    <prop key="mail.debug">true</prop>
    <prop key="mail.pop3.port">995</prop>
    <prop key="mail.pop3.socketFactory.class">javax.net.ssl.SSLSocketFactory</prop>
    <prop key="mail.pop3.socketFactory.port">995</prop>
  </util:properties>

</beans>

Again, note the use of the Spring util namespace to populate the Java mail properties to enable SSL protocol. Similar to the other inbound mail adapter examples, a simple main class is created to demonstrate the POP3 mail adapter. The example class is shown in Listing 13–7, where the Spring context is created and used to subscribe to the inputChannel message channel. Any incoming e-mail messages will be logged by this code.

Listing 13–7. POP3 E-mail Receiving main Class PopMail

package com.apress.prospringintegration.social.mail;

import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.Message;
import org.springframework.integration.MessagingException;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.core.MessageHandler;

public class PopMail {
    private static Logger LOG = Logger.getLogger(PopMail.class);

    public static void main(String[] args) throws Exception {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("/spring/mail/pop-mail.xml");

        DirectChannel inputChannel = context.getBean("inputChannel", DirectChannel.class);

        inputChannel.subscribe(new MessageHandler() {
            public void handleMessage(Message<?> message) throws MessagingException {
                LOG.info("Message: " + message);
            }
        });
    }
}

SMTP

The e-mail outbound-channel-adapter uses the SMTP protocol to send e-mail messages. One of the most important concepts to grasp when using this adapter is the default message mapping strategies. If the input message payload is an instance of the org.springframework.mail.MailMessage interface, it will be sent directly. A byte array message payload will be sent as an e-mail attachment. A string payload will be mapped to text-based e-mail content. More complex e-mail content will require a message transformation as discussed earlier in the book.

The different e-mail parameters are configured through the message header. An e-mail-specific header-enricher transformer is available in the mail namespace. This enricher allows setting e-mail parameters such as to, cc, bcc, from, and reply-to. An example of the e-mail outbound-channel-adapter is shown in Listing 13–8. This example is configured for the Gmail server.

Listing 13–8. Sending E-mail with SMTP Spring Configuration smtp-mail.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:int="http://www.springframework.org/schema/integration"
       xmlns:mail="http://www.springframework.org/schema/integration/mail"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/integration
    http://www.springframework.org/schema/integration/spring-integration-2.0.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/integration/mail
    http://www.springframework.org/schema/integration/mail/spring-integration-mail-2.0.xsd
    http://www.springframework.org/schema/util
    http://www.springframework.org/schema/util/spring-util-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

  <context:component-scan base-package="com.apress.prospringintegration.social.mail"/>

  <int:channel id="input"/>

  <int:channel id="outboundMail"/>

  <mail:outbound-channel-adapter channel="outboundMail"
                                 mail-sender="mailSender"/>

  <mail:header-enricher input-channel="input" output-channel="outboundMail">
    <mail:to value="[username]@gmail.com"/>
    <mail:from value="[username]@gmail.com"/>
    <mail:subject value="Test"/>
  </mail:header-enricher>

</beans>

The outbound adapter requires an instance of Spring’s org.springframework.mail.javamail.JavaMailSender. Spring Java configuration is used to create the instance as shown in Listing 13–9. This configuration is specifically set up for Gmail’s security requirements.

Listing 13–9. Java Configuration MailConfiguration for Creating the JavaMailSender Instance

package com.apress.prospringintegration.social.mail;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;

import java.util.Properties;

@Configuration
public class MailConfiguration {

    @Bean
    public JavaMailSenderImpl mailSender() {
        JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
        mailSender.setHost("smtp.gmail.com");
        mailSender.setPort(587);
        mailSender.setUsername("[username]@gmail");
        mailSender.setPassword("[password]");
        Properties properties = new Properties();
        properties.setProperty("mail.smtp.starttls.enable", "true");
        properties.setProperty("mail.smtp.auth", "true");
        mailSender.setJavaMailProperties(properties);
        return mailSender;
    }
}

Listing 13–10 shows the test code for sending an e-mail using the Spring configuration file in Listing 13–9. The test code sends a message to the input channel with the text string “This is a test.” The result will be an e-mail message sent with the previous text string.

Listing 13–10. E-mail Sending Test Code

package com.apress.prospringintegration.social.mail;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.support.MessageBuilder;

public class SmtpMail {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                "/spring/mail/smtp-mail.xml", SmtpMail.class);

        MessageChannel input = context.getBean("input", MessageChannel.class);
        Message<String> message = MessageBuilder.withPayload("This is a test").build();
        input.send(message);

        context.stop();
    }
}

XMPP

Spring Integration enables sending and receiving XMPP messages supported by Instant Messaging (IM) networks such as GTalk and Facebook Chat. In addition, Spring Integration supports broadcasting and receiving state using the presence adapters. XMPP support requires an additional Maven dependency, as shown in Listing 13–11.

Listing 13–11. Maven Dependency for XMPP Support

    <dependency>
      <groupId>org.springframework.integration</groupId>
      <artifactId>spring-integration-xmpp</artifactId>
      <version>2.0.1.RELEASE</version>
    </dependency>

In order to communicate with an XMPP server, a connection factory must first be configured. This is best done with Spring Java configuration, as shown in Listing 13–12. This configuration is specifically directed at GTalk and SASL authentication mechanism. Spring XMPP support is based on the Smack 3.1 API (www.igniterealtime.org/downloads/index.jsp). Java configuration is well suited for the XMPP adapters, due to the large number of potential configuration parameters and the static initializers.

Listing 13–12. Java Configuration XmppConfiguration for XMPP Connection Factory

package com.apress.prospringintegration.social.xmpp;

import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.SASLAuthentication;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.xmpp.config.XmppConnectionFactoryBean;

@Configuration
public class XmppConfiguration {

    @Value("${host}")
    private String host;

    @Value("${port}")
    private int port;

    @Value("${service-name}")
    private String serviceName;

    @Value("${resource}")
    private String resource;

    @Value("${subscription-mode}")
    private String subscriptionMode;

    @Value("${user}")
    private String user;

    @Value("${password}")
    private String password;

    @Value("${sasl-mechanism-supported")
    private String saslMechanismSupported;

    @Value("${sasl-mechanism-supported-index}")
    private int saslMechanismSupportedIndex;

    @Bean
    public XmppConnectionFactoryBean xmppConnectionFactoryBean() {
        SASLAuthentication.supportSASLMechanism(saslMechanismSupported,
                saslMechanismSupportedIndex);
        ConnectionConfiguration connectionConfiguration =
                new ConnectionConfiguration(host, port, serviceName);
        XmppConnectionFactoryBean connectionFactoryBean =
                new XmppConnectionFactoryBean(connectionConfiguration);
        connectionFactoryBean.setResource(resource);
        connectionFactoryBean.setSubscriptionMode(subscriptionMode);
        connectionFactoryBean.setUser(user);
        connectionFactoryBean.setPassword(password);

        return connectionFactoryBean;
    }
}

The various configuration values are passed to the Java configuration using @Value attribute and a properties file. The specific properties for GTalk are shown in Listing 13–13.

Listing 13–13. XMPP Configuration Properties File xmpp.properties

user=[username]@gmail.com
password=[password]
host=talk.google.com
port=5222
subscription-mode=accept_all
sasl-mechanism-supported=PLAIN
sasl-mechanism-supported-index=0
resource=resource
service-name=gmail.com

An example of configuration Spring Integration for receiving a XMPP message from the GTalk server is shown in Listing 13–14. Note the additional namespace element required to support XMPP. The xmppinbound-channel-adapter is configured to use the xmppConnectionFactoryBean discussed previously. The inbound adapter is configured to extract the message as an org.springframework.integration.twitter.core.Tweet object and sent as a payload to the xmppChannel.

Listing 13–14. Receiving XMPP Message Spring Configuration xmpp-inbound.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:int="http://www.springframework.org/schema/integration"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:xmpp="http://www.springframework.org/schema/integration/xmpp"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/integration/xmpp
    http://www.springframework.org/schema/integration/xmpp/spring-integration-xmpp-2.0.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/integration
    http://www.springframework.org/schema/integration/spring-integration-2.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

  <context:component-scan base-package="com.apress.prospringintegration.social.xmpp"/>
  <context:property-placeholder location="/spring/xmpp/xmpp.properties"/>

  <int:channel id="xmppInbound"/>

  <xmpp:inbound-channel-adapter extract-payload="true"
                                channel="xmppInbound"
                                xmpp-connection="xmppConnectionFactoryBean"/>

  <int:service-activator input-channel="xmppInbound"
                         ref="xmppMessageConsumer"/>

</beans>

The message is received by the XmppMessageConsumer service activator, as shown in Listing 13–15. The service activator is configured using annotations and component scanning. The service activator extracts the payload and logs the message text and the sender of the message.

Listing 13–15. XMPP Message Consumer Class XmppMessageConsumer

package com.apress.prospringintegration.social.twitter;

import org.apache.log4j.Logger;
import org.springframework.integration.Message;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.twitter.core.Tweet;
import org.springframework.stereotype.Component;

@Component
public class TwitterMessageConsumer {
    private static Logger LOG = Logger.getLogger(TwitterMessageConsumer.class);

    @ServiceActivator
    public void consume(Message<Tweet> message) {
        Tweet tweet = message.getPayload();
        LOG.info(tweet.getText() + " from: " + tweet.getFromUser());
    }
}

The test code to load the Spring configuration and wait for the XMPP messages is shown in Listing 13–16. Any XMPP message that is sent to the account specified in the XmppConfiguration Java configuration file will be logged.

Listing 13–16. Receiving XMPP Message Test Code

package com.apress.prospringintegration.social.xmpp;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class XmppInbound {

    public static void main(String[] args) throws Exception {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("/spring/xmpp/xmpp-inbound.xml");

        Thread.sleep(10 * 60 * 1000);
    }
}

In a similar fashion, messages can be sent to users on XMPP. The same XmppConfiguration Java configuration is used to connect to the GTalk server, as shown in Listing 13–17. The xmpp outbound-channel-adapter is configured to send the payload of the incoming message on the xmppOutbound channel. A specific XMPP header-enricher via the message-to element is used to specify the user that is to receive the XMPP message.

Listing 13–17. Sending XMPP Message Spring Configurationxmpp-outbound.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:int="http://www.springframework.org/schema/integration"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:xmpp="http://www.springframework.org/schema/integration/xmpp"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/integration/xmpp
    http://www.springframework.org/schema/integration/xmpp/spring-integration-xmpp-2.0.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/integration
    http://www.springframework.org/schema/integration/spring-integration-2.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

  <context:component-scan base-package="com.apress.prospringintegration.social.xmpp"/>
  <context:property-placeholder location="/spring/xmpp/xmpp.properties"/>

  <int:channel id="xmppOutbound"/>
  <int:channel id="input"/>

  <xmpp:outbound-channel-adapter channel="xmppOutbound"
                                 xmpp-connection="xmppConnectionFactoryBean"/>

  <xmpp:header-enricher input-channel="input" output-channel="xmppOutbound">
    <xmpp:chat-to value="[username]@gmail.com"/>
  </xmpp:header-enricher>

</beans>

Listing 13–18 shows test code that will send a message to the XMPP user specified in the previous Spring configuration file. A message will be sent to the input message channel, the header message-to will set the user destination, and the message will be sent to the GTalk using xmpp outbound-channel-adapter.

Listing 13–18. Sending XMPP Message Test Code

package com.apress.prospringintegration.social.xmpp;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.support.MessageBuilder;

public class XmppOutbound {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                "/spring/xmpp/xmpp-outbound.xml", XmppOutbound.class);

        MessageChannel input = context.getBean("input", MessageChannel.class);
        Message<String> message = MessageBuilder.withPayload("This is a test").build();
        input.send(message);

        context.stop();
    }
}

Spring Integration also support broadcasting and receiving state. This allows IM users to let others on their roster know their current state. For example, if an IM user is unavailable to chat, they may broadcast an “away” state. This will be reflected in the roster status in everyone’s IM client. The Spring Integration presence adapters are used to send and receive notifications of IM state changes.

To monitor what the current status of the others users in your roster, Spring Integration provides a presence-inboud-channel-adapter. The XMPP presence adapter shown in Listing 13–19 uses the same connection factory as the previous examples. The adapter sends the status of users in the roster as a org.jivesoftware.smack.packet.Presence object (see www.igniterealtime.org/builds/smack/docs/3.1.0/javadoc/org/jivesoftware/smack/packet/Presence.html) to the message channel xmppInbound.

Listing 13–19. Spring Configuration xmpp-presence-inbound.xml for Receiving State

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:int="http://www.springframework.org/schema/integration"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:xmpp="http://www.springframework.org/schema/integration/xmpp"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/integration/xmpp
    http://www.springframework.org/schema/integration/xmpp/spring-integration-xmpp-2.0.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/integration
    http://www.springframework.org/schema/integration/spring-integration-2.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

  <context:component-scan base-package="com.apress.prospringintegration.social.xmpp"/>
  <context:property-placeholder location="/spring/xmpp/xmpp.properties"/>

  <int:channel id="xmppInbound"/>

  <xmpp:presence-inbound-channel-adapter channel="xmppInbound"
                                         xmpp-connection="xmppConnectionFactoryBean"/>

  <int:service-activator input-channel="xmppInbound"
                         ref="xmppMessageConsumer"/>

</beans>

A service activator is configured to send the message sent to the message channel xmppInbound to the Spring bean xmppMessageConsumer, which is shown in Listing 13–20. This service activator logs the status of the users on your roster.

Listing 13–20. Service activator XmppMessageConsumer which Logs the XMPP Presence Message

package com.apress.prospringintegration.social.xmpp;

import org.apache.log4j.Logger;
import org.springframework.integration.Message;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.stereotype.Component;

@Component
public class XmppPresenceConsumer {
    private static Logger LOG = Logger.getLogger(XmppMessageConsumer.class);

    @ServiceActivator
    public void consume(Message<?> input) {
        LOG.info("Received message: " + input);
    }
}

The example may be run using the simple main class XmppPresenceConsumer shown in Listing 13–21. This will list the status of the various users on your roster and any status updates thereafter.

Listing 13–21. Inbound Presence Example main Class XmppPresenceInbound

package com.apress.prospringintegration.social.xmpp;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class XmppPresenceInbound {

    public static void main(String[] args) throws Exception {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("/spring/xmpp/xmpp-presence-inbound.xml");

        Thread.sleep(10 * 60 * 1000);
    }
}

In the same manner, the user’s status may be broadcasted to all the other users on the user’s roster. This is done using the presence-outbound-channel-adapter. Again the XMPP configuration factory created by the Spring Java configuration file is used. The outbound adapter takes the same Presence object discussed for the inbound adapter and broadcasts the status to all the users on your roster. See Listing 13–22.

Listing 13–22. Spring Configuration xmpp-presence-outbound.xml for Broadcasting Status

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:int="http://www.springframework.org/schema/integration"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:xmpp="http://www.springframework.org/schema/integration/xmpp"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/integration/xmpp
    http://www.springframework.org/schema/integration/xmpp/spring-integration-xmpp-2.0.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/integration
    http://www.springframework.org/schema/integration/spring-integration-2.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

  <context:component-scan base-package="com.apress.prospringintegration.social.xmpp"/>
  <context:property-placeholder location="/spring/xmpp/xmpp.properties"/>

  <int:channel id="xmppOutbound"/>

  <xmpp:presence-outbound-channel-adapter channel="xmppOutbound"
                                          xmpp-connection="xmppConnectionFactoryBean"/>

</beans>

The XMPP outbound adapter may be tested using the example main class shown in Listing 13–23. A Presence object is instantiated with Presence.Type.available where the user is subscribed to the XMPP server, the message “Out to Lunch,” which will appear in the other users’ client, and a Presence.Mode.away, which will be the displayed status. Running this example will broadcast this status to all of the users on their roster.

Listing 13–23. Outbound Presence Example main Class XmppPresenceOutbound

package com.apress.prospringintegration.social.xmpp;

import org.jivesoftware.smack.packet.Presence;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.support.MessageBuilder;

public class XmppPresenceOutbound {

    public static void main(String[] args) throws Exception {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                "/spring/xmpp/xmpp-presence-outbound.xml", XmppOutbound.class);

        MessageChannel input = context.getBean("xmppOutbound", MessageChannel.class);

        Presence presence =
                new Presence(Presence.Type.available, "Out to lunch", 0, Presence.Mode.away);
        Message<Presence> message = MessageBuilder.withPayload(presence).build();

        input.send(message);

        Thread.sleep(10 * 60 * 1000);
    }
}

Twitter

Spring Integration can also send and receive “tweets.” The Maven dependency is shown in Listing 13–24.

Listing 13–24. Maven Dependency for Twitter Support

    <dependency>
      <groupId>org.springframework.integration</groupId>
      <artifactId>spring-integration-twitter</artifactId>
      <version>2.0.1.RELEASE</version>
    </dependency>

Spring Integration supports sending and receiving Twitter updates, direct messages (DM), and mentions (tweets that include somebody else’s Twitter handle preceded by a “@”). Twitter updates are the standard tweet that users send out to all their followers. DMs are private messages sent directly to a user. A DM does not appear in the public timeline and the recipient of a DM must also be a follower of the sender. Mentions are tweets that are directed at or in response to a particular person using the familiar @username symbol. These messages can be seen by all, but show up in the reply tab of the intended recipient.

All of the Twitter adapters require a Twitter template that will be configured using Spring Java configuration, as shown in Listing 13–25. The twitterTemplate bean requires a set of authorization keys that may be obtained by request at http://dev.twitter.com/pages/auth. For the purpose of this example, the keys are provided for the Twitter account @prosibook.

Listing 13–25. Java Configuration TwitterConfiguration used to Configure Twitter Template

package com.apress.prospringintegration.social.twitter;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.twitter.core.Twitter4jTemplate;
import org.springframework.integration.twitter.core.TwitterOperations;

@Configuration
public class TwitterConfiguration {

    @Value("${consumer-key}")
    private String consumerKey;

    @Value("${consumer-secret}")
    private String consumerSecret;

    @Value("${access-token}")
    private String accessToken;

    @Value("${access-token-secret}")
    private String accessTokenSecret;

    @Bean
    public TwitterOperations twitterTemplate() {
        Twitter4jTemplate twitterOperations =
                new Twitter4jTemplate(
                        consumerKey, consumerSecret, accessToken, accessTokenSecret);
        return twitterOperations;

    }
}

The Twitter keys are defined in the properties file shown in Listing 13–26. These keys are used to authenticate and authorize the user.

Listing 13–26. Properties File twitter.properties Defining Twitter Keys

consumer-key=SZHVUR5O6Awq2cJJvPZEA
consumer-secret=iXwGDkJdWuCzsXFfZpAtqfFygPBB5QkdUhLsvbsyEA
access-token=184204629-C1cyGIrfmppJNu1WdASZ1bQaAvYr0YLzHxXPvEcQ
access-token-secret=Y25kBcxolzqu76wZI3D1iDSEloCGkcUtlDv9Q7K9wo

Using Spring Integration, a channel message may be converted into a Twitter update, DM, or mention using the Twitter outbound adapter. The outbound-channel-adapter is configured in Listing 13–27 to send the incoming channel message on twitterOutbound to Twitter as an updated to @prosibook. In addition, note the required twitter namespace that has been added to the configuration file.

Listing 13–27. Sending Twitter Update Message Spring Configuration twitter-outbound.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:int="http://www.springframework.org/schema/integration"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:twitter="http://www.springframework.org/schema/integration/twitter"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/integration/twitter
    http://www.springframework.org/schema/integration/twitter/spring-integration-twitterimages
-2.0.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/integration
    http://www.springframework.org/schema/integration/spring-integration-2.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

  <context:component-scan base-package="com.apress.prospringintegration.social.twitter"/>
  <context:property-placeholder location="/spring/twitter/twitter.properties"/>

  <int:channel id="twitterOutbound"/>

  <twitter:outbound-channel-adapter twitter-template="twitterTemplate"
                                    channel="twitterOutbound"/>

</beans>

To test the Twitter update Spring configuration, a simple test class is required. This is shown in Listing 13–28. It simply sends a text message to the twitterOutbound message channel that will result in a tweet being posted to the @prosibook account. Note the addition of the current timestamp to the outbound message. This is required, because the same update cannot be sent twice to Twitter in a certain time window.

Listing 13–28. Sending Twitter Update Message Test Code TwitterOutbound

package com.apress.prospringintegration.social.twitter;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.support.MessageBuilder;

import java.util.Calendar;

public class TwitterOutbound {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                "/spring/twitter/twitter-outbound.xml", TwitterOutbound.class);

        MessageChannel input = context.getBean("twitterOutbound", MessageChannel.class);
        Message<String> message =
                MessageBuilder.withPayload("Only can send message once " +
                        Calendar.getInstance().getTimeInMillis()).build();
        input.send(message);

        context.stop();
    }
}

The next outbound adapter provides support for sending a DM to a Twitter account. This will send a private message to a specific user who is also a follower. The configuration is similar to update adapter, except it uses the outbound-dm-channel adapter. The Spring configuration file is shown in Listing 13–29.

Listing 13–29. Sending Twitter DM Spring Configuration twitter-dm-outbound.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:int="http://www.springframework.org/schema/integration"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:twitter="http://www.springframework.org/schema/integration/twitter"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/integration/twitter
    http://www.springframework.org/schema/integration/twitter/spring-integration-twitterimages
-2.0.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/integration
    http://www.springframework.org/schema/integration/spring-integration-2.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

  <context:component-scan base-package="com.apress.prospringintegration.social.twitter"/>
  <context:property-placeholder location="/spring/twitter/twitter.properties"/>

  <int:channel id="twitterOutbound"/>

  <twitter:dm-inbound-channel-adapter channel="twitterOutbound"
                                      twitter-template="twitterTemplate"/>

</beans>

The target user is set through the header TwitterHeaders.DM_TARGET_USER_ID. The test code shown in Listing 13–30 sets the header value programmatically to send a DM to @prosibook.

Listing 13–30. Sending Twitter DM Test Code TwitterDmOutbound

package com.apress.prospringintegration.social.twitter;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.integration.twitter.core.TwitterHeaders;

public class TwitterDmOutbound {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                "/spring/twitter/twitter-outbound.xml", TwitterOutbound.class);

        MessageChannel input = context.getBean("twitterOutbound", MessageChannel.class);
        Message<String> message = MessageBuilder.withPayload("This is a test")
                .setHeader(TwitterHeaders.DM_TARGET_USER_ID, "@prosibook").build();
        input.send(message);

        context.stop();
    }
}

Spring Integration can also receive Twitter messages. The Spring configuration for receiving a Twitter update is shown in Listing 13–31. The inbound-update-channel-adapter is configured with the same twitter-template to send the Twitter update message to the twitterInbound channel. A poller element is required to pull the messages from the Twitter server.

Listing 13–31. Receiving Twitter Update Message Spring Configuration twitter-inbound.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:int="http://www.springframework.org/schema/integration"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:twitter="http://www.springframework.org/schema/integration/twitter"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/integration/twitter
    http://www.springframework.org/schema/integration/twitter/spring-integration-twitterimages
-2.0.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/integration
    http://www.springframework.org/schema/integration/spring-integration-2.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

  <context:component-scan base-package="com.apress.prospringintegration.social.twitter"/>
  <context:property-placeholder location="/spring/twitter/twitter.properties"/>

  <int:channel id="twitterInbound"/>

  <twitter:inbound-channel-adapter channel="twitterInbound"
                                   twitter-template="twitterTemplate">
    <int:poller fixed-rate="5000" max-messages-per-poll="3"/>
  </twitter:inbound-channel-adapter>

  <int:service-activator input-channel="twitterInbound" ref="twitterMessageConsumer"/>

</beans>

The service activator class is used to receive the Twitter message, as shown in Listing 13–32. The same class may be used for the incoming Twitter update, DM, and mention.

Listing 13–32. Twitter Message Consumer Class TwitterMessageConsumer

package com.apress.prospringintegration.social.twitter;

import org.apache.log4j.Logger;
import org.springframework.integration.Message;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.twitter.core.Tweet;
import org.springframework.stereotype.Component;

@Component
public class TwitterMessageConsumer {
    private static Logger LOG = Logger.getLogger(TwitterMessageConsumer.class);

    @ServiceActivator
    public void consume(Message<Tweet> message) {
        Tweet tweet = message.getPayload();
        LOG.info(tweet.getText() + " from: " + tweet.getFromUser());
    }
}

All that is required to run the Twitter inbound message example is to load the Spring configuration file, as shown in Listing 13–33. A ten-minute delay is added to the code to wait for any new tweets.

Listing 13–33. Twitter Message Consumer Test Code TwitterInbound

package com.apress.prospringintegration.social.twitter;

import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TwitterInbound {
    private static Logger LOG = Logger.getLogger(TwitterInbound.class);

    public static void main(String[] args) throws Exception {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("/spring/twitter/twitter-inbound.xml");

        Thread.sleep(10 * 60 * 1000);
    }
}

Receiving the Twitter DM is identical to receiving an update except for using the inbound-dm-channel-adapter. An example of a Spring configuration for receiving a Twitter DM is shown in Listing 13–34. Again, this adapter requires a poller element to pull the messages from Twitter.

Listing 13–34. Receiving Twitter DM Spring Configuration

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:int="http://www.springframework.org/schema/integration"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:twitter="http://www.springframework.org/schema/integration/twitter"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/integration/twitter
    http://www.springframework.org/schema/integration/twitter/spring-integration-twitterimages
-2.0.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/integration
    http://www.springframework.org/schema/integration/spring-integration-2.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

  <context:component-scan base-package="com.apress.prospringintegration.social.twitter"/>
  <context:property-placeholder location="/spring/twitter/twitter.properties"/>

  <int:channel id="twitterInbound"/>

  <twitter:dm-inbound-channel-adapter twitter-template="twitterTemplate"
                                      channel="twitterInbound">
    <int:poller fixed-rate="5000" max-messages-per-poll="3"/>
  </twitter:dm-inbound-channel-adapter>

  <int:service-activator input-channel="twitterInbound" ref="twitterMessageConsumer"/>

</beans>

The Twitter DM inbound example may be tested using the main class shown in Listing 13–35. Again a ten-minute delay is added to the code to wait for incoming DMs.

Listing 13–35. Receiving Twitter DM Example main Class TwitterDmInbound

package com.apress.prospringintegration.social.twitter;

import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TwitterDmInbound {
    private static Logger LOG = Logger.getLogger(TwitterDmInbound.class);

    public static void main(String[] args) throws Exception {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("/spring/twitter/twitter-dm-inbound.xml");

        Thread.sleep(10 * 60 * 1000);
    }
}

An example of receiving Twitter mention messages is shown in Listing 13–36. The inbound-mention-channel-adapter is used to receive the mentions using a configuration identical to the other inbound Twitter adapters.

Listing 13–36. Receiving Twitter Mention Message Spring Configuration twitter-mention-inbound.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:int="http://www.springframework.org/schema/integration"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:twitter="http://www.springframework.org/schema/integration/twitter"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/integration/twitter
    http://www.springframework.org/schema/integration/twitter/spring-integration-twitterimages
-2.0.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/integration
    http://www.springframework.org/schema/integration/spring-integration-2.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

  <context:component-scan base-package="com.apress.prospringintegration.social.twitter"/>
  <context:property-placeholder location="/spring/twitter/twitter.properties"/>

  <int:channel id="twitterInbound"/>

  <twitter:mentions-inbound-channel-adapter channel="twitterInbound"
                                            twitter-template="twitterTemplate">
    <int:poller fixed-rate="5000" max-messages-per-poll="3"/>
  </twitter:mentions-inbound-channel-adapter>

  <int:service-activator input-channel="twitterInbound" ref="twitterMessageConsumer"/>

</beans>

Again, a main class is used to create the Spring context and wait for ten minutes for any incoming Twitter mentions. The example main class is shown in Listing 13–37.

Listing 13–37. Receiving Twitter Mentions Example class TwitterMentionInbound

package com.apress.prospringintegration.social.twitter;

import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TwitterMentionInbound {
    private static Logger LOG = Logger.getLogger(TwitterMentionInbound.class);

    public static void main(String[] args) throws Exception {
        ApplicationContext context =
                new ClassPathXmlApplicationContext(
                        "/spring/twitter/twitter-mention-inbound.xml");

        Thread.sleep(10 * 60 * 1000);
    }
}}

The final Twitter adapter that will be discussed is inbound search adapter. This adapter can do Twitter searches based on a query. More information about Twitter queries may be found at http://search.twitter.com/operators. The Spring configuration file for an inbound Twitter search adapter is shown in Listing 13–38. Note that this adapter does not require a reference to a twitter-template, because a search is anonymous.

Listing 13–38. Spring Configuration twitter-search-inbound.xml Demostrating a Twitter Search

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:int="http://www.springframework.org/schema/integration"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:twitter="http://www.springframework.org/schema/integration/twitter"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/integration/twitter
    http://www.springframework.org/schema/integration/twitter/spring-integration-twitterimages
-2.0.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/integration
    http://www.springframework.org/schema/integration/spring-integration-2.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

  <context:component-scan base-package="com.apress.prospringintegration.social.twitter"/>

  <int:channel id="twitterInbound"/>

  <twitter:search-inbound-channel-adapter query="#springintegration"
                                          channel="twitterInbound">
    <int:poller fixed-rate="5000" max-messages-per-poll="3"/>
  </twitter:search-inbound-channel-adapter>

  <int:service-activator input-channel="twitterInbound" ref="twitterMessageConsumer"/>

</beans>

The inbound Twitter search adapter may be tested using the example main class shown in Listing 13–39. This example will list the search results from the query defined in the search-inbound-channel-adapter shown previously.

Listing 13–39. Example main Class TwitterSearchInbound Demostrating a Twitter Search

package com.apress.prospringintegration.social.twitter;

import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TwitterSearchInbound {
    private static Logger LOG = Logger.getLogger(TwitterInbound.class);

    public static void main(String[] args) throws Exception {
        ApplicationContext context =
                new ClassPathXmlApplicationContext(
                        "/spring/twitter/twitter-search-inbound.xml");

        Thread.sleep(10 * 60 * 1000);
    }
}

News Feed

Spring Integration provides support for Web Syndication by supplying a feed adapter that enables subscribing to an RSS or ATOM feed. RSS and ATOM are useful for broadcasting events. Most often this takes the form of news feeds, but it could also be a system log of application events. for example. The following Maven dependency shown in Listing 13–41 is required for the feed adapter.

Listing 13–40. Addition Maven Dependency for RSS Feed

    <dependency>
      <groupId>org.springframework.integration</groupId>
      <artifactId>spring-integration-feed</artifactId>
    </dependency>

The feed adapter is configured by supplying the URL of the RSS feed of interest and the channel where the feed will be sent. An example Spring configuration for a feed adapter is shown in Listing 13–41. Note the additional feed namespace used for the feed adapter. The feed adapter will listen to the RSS feed at http://feeds.nytimes.com/nyt/rss/Technolgy and will send a message to the channel feedChannel. The message will have a payload of the type com.sun.syndication.feed.syn.SyndEntry, which encapsulates information about the news item including content, dates, and authors. A poller element is required for the feed adapter, because it is a poller consumer.

Note that the feed adapter is slightly different than other polling consumers. When the feed adapter is first started and does its first poll, a com .sun.syndication.feed.synd.SyndEntryFeed instance is received. This object contains multiple SyndEntry objects and each entry is stored in a local entry queue and released based on the max-messages-per-poll property of the poller. This queue will be refreshed if it becomes empty and there are additional new entries available.

Listing 13–41. Spring Configuration feed-inbound.xml for Following a RSS Feed

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:int="http://www.springframework.org/schema/integration"
       xmlns:feed="http://www.springframework.org/schema/integration/feed"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd     http://www.springframework.org/schema/integration
    http://www.springframework.org/schema/integration/spring-integration-2.0.xsd
    http://www.springframework.org/schema/integration/feed
    http://www.springframework.org/schema/integration/feed/spring-integration-feed-2.0.xsd">

  <int:channel id="feedChannel">
    <int:queue/>
  </int:channel>

  <feed:inbound-channel-adapter id="feedAdapter"
                                    channel="feedChannel"
                                    url="http://feeds.nytimes.com/nyt/rss/Technology">
    <int:poller fixed-rate="10000" max-messages-per-poll="100"/>
  </feed:inbound-channel-adapter>

</beans>

Spring Integration also provides a mechanism to prevent duplicate entries. Each feed entry has an associated published date field. Each time the feed adapter creates a new message object, the feed adapter stores the latest published date in an instance of org.springframework.integration.core.store.MetadataStore. The feed adapter will look at this data store before creating and sending a message to insure that no duplicate entries are sent. By default, Spring Integration will the Metadatastore implementation SimpleMetadataStore, which is an in-memory implementation. This datastore will be lost if the adapter is restarted. Otherwise the properties file based PropertiesPersistingMetadataStore. For example, the property-based persister may be configured using Java configuration as shown in Listing 13–42.

Listing 13–42. Property Base Persistence Configuration

package com.apress.prospringintegration.social.feed;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.store.PropertiesPersistingMetadataStore;

@Configuration
public class FeedConfiguration {

    @Bean
    public PropertiesPersistingMetadataStore metadataStore() {
        PropertiesPersistingMetadataStore metadataStore =
                new PropertiesPersistingMetadataStore();
        return metadataStore;
    }
}

The feed adapter may be tested using the main class shown in Listing 13–43. The Spring context is created and the messages are pulled from the message channel feedChannel. The payload coming from the feed adapter is of the type SyndEntry. The main class logs the published date and the title of the entry. Additional information such as the context may also be derived from the SyndEntry instance.

Listing 13–43. Example main Class FeedInboundApp for Following an RSS Feed

package com.apress.prospringintegration.social.feed;

import com.sun.syndication.feed.synd.SyndEntry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.Message;
import org.springframework.integration.core.PollableChannel;

public class FeedInboundApp {

    public static void main(String[] args) {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("/spring/feed/feed-inbound.xml");

        PollableChannel feedChannel = context.getBean("feedChannel", PollableChannel.class);

        for (int i = 0; i < 10; i++) {
            Message<SyndEntry> message = (Message<SyndEntry>) feedChannel.receive(1000);
            if (message != null) {
                SyndEntry entry = message.getPayload();
                System.out.println(entry.getPublishedDate() + " - " + entry.getTitle());
            } else {
                break;
            }
        }
    }
}

Summary

This chapter has covered the current support in Spring Integration for social computing. Social computing is becoming a part of everyone’s life, and dominates a large part of the Internet bandwidth. Its growth is expanding with the mobile market. Spring Integration provides support for e-mail, XMPP, RSS, and Twitter, and this chapter has introduced how these technologies may become a part of enterprise integration.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.219.239.118