27. Twitter Adapter

Spring Integration provides support for interacting with Twitter. With the Twitter adapters you can both
receive and send Twitter messages. You can also perform a Twitter search based on a schedule and publish
the search results within Messages.

27.1 Introduction

Twitter is a social networking and micro-blogging service that enables its users to send and read messages known as tweets.
Tweets are text-based posts of up to 140 characters displayed on the author's profile page and delivered to the author's
subscribers who are known as followers.

Important

Previous versions of Spring Integration were dependent upon the Twitter4J API,
but with the release of Spring Social 1.0 GA,
Spring Integration, as of version 2.1, now builds directly upon Spring Social's Twitter support, instead of Twitter4J.

Spring Integration provides a convenient namespace configuration to define Twitter artifacts. You can enable it by adding
the following within your XML header.

27.2 Twitter OAuth Configuration

The Twitter API allows for both authenticated and anonymous operations. For authenticated operations Twitter uses OAuth
- an authentication protocol that allows users to approve an application to act on their behalf without
sharing their password. More information can be found at http://oauth.net/ or
in this article http://hueniverse.com/oauth/ from Hueniverse.
Please also see OAuth FAQ for more information about OAuth and Twitter.

In order to use OAuth authentication/authorization with Twitter you must create a new Application on the Twitter Developers site.
Follow the directions below to create a new application and obtain consumer keys and an access token:

Click on the Register an app link and fill out all required fields on the form provided;
set Application Type to Client and depending on the nature of your application select
Default Access Type as Read & Write or Read-only
and Submit the form. If everything is successful you'll be presented with the Consumer Key
and Consumer Secret. Copy both values in a safe place.

On the same page you should see a My Access Token button on the side bar (right).
Click on it and you'll be presented with two more values: Access Token and Access Token Secret.
Copy these values in a safe place as well.

27.3 Twitter Template

As mentioned above, Spring Integration relies upon Spring Social, and that library provides an implementation of the template
pattern, org.springframework.social.twitter.api.impl.TwitterTemplate to interact with Twitter.
For anonymous operations (e.g., search), you don't have to define an instance of TwitterTemplate explicitly,
since a default instance will be created and injected into the endpoint. However, for authenticated operations
(update status, send direct message, etc.), you must configure a TwitterTemplate as a bean and
inject it explicitly into the endpoint, because the authentication configuration is required.
Below is a sample configuration of TwitterTemplate:

As you can see from the configuration above, all we need to do is to provide
OAuth attributes as constructor arguments. The values would be those you obtained in the previous step.
The order of constructor arguments is: 1) consumerKey, 2) consumerSecret,
3) accessToken, and 4) accessTokenSecret.

A more practical way to manage OAuth connection attributes would be via Spring's property placeholder support by simply
creating a property file (e.g., oauth.properties):

27.4 Twitter Inbound Adapters

The current release of Spring Integration provides support for receiving tweets as Timeline Updates,
Direct Messages, Mention Messages as well as Search Results.

Every Inbound Twitter Channel Adapter is a Polling Consumer which means you have to provide a poller
configuration. However, there is one important thing you must understand about Twitter since its inner-workings are slightly
different than other polling consumers. Twitter defines a concept of Rate Limiting. You can read more about
it here: Rate Limiting. In a nutshell, Rate Limiting
is the way Twitter manages how often an application can poll for updates. You should consider this when setting your
poller intervals, but we are also doing a few things to limit excessively aggressive polling within our adapters.

Another issue that we need to worry about is handling duplicate Tweets. The same adapter (e.g., Search or Timeline Update)
while polling on Twitter may receive the same values more than once. For example if you keep searching on Twitter with the same search
criteria you'll end up with the same set of tweets unless some other new tweet that matches your search criteria was posted
in between your searches. In that situation you'll get all the tweets you had before plus the new one. But what you really
want is only the new tweet(s). Spring Integration provides an elegant mechanism for handling these situations.
The latest Tweet timestamp will be stored in an instance of the org.springframework.integration.store.MetadataStore which is a
strategy interface designed for storing various types of metadata (e.g., last retrieved tweet in this case). That strategy helps components such as
these Twitter adapters avoid duplicates. By default, Spring Integration will look for a bean of type
org.springframework.integration.store.MetadataStore in the ApplicationContext.
If one is found then it will be used, otherwise it will create a new instance of SimpleMetadataStore
which is a simple in-memory implementation that will only persist metadata within the lifecycle of the currently running application context.
That means upon restart you may end up with duplicate entries. If you need to persist metadata between Application Context
restarts, you may use the PropertiesPersistingMetadataStore (which is backed by a properties file, and a persister
strategy), or you may create your own custom implementation of the MetadataStore interface (e.g., JdbcMetadatStore)
and configure it as a bean named 'metadataStore' within the Application Context.

Here is a link that will help you learn more about Twitter queries: http://search.twitter.com/operators

As you can see the configuration of all of these adapters is very similar to other inbound adapters with one exception.
Some may need to be injected with the twitter-template. Once received each Twitter Message would be
encapsulated in a Spring Integration Message and sent to the channel specified by the channel attribute.
Currently the Payload type of any Message is org.springframework.integration.twitter.core.Tweet
which is very similar to the object with the same name in Spring Social. As we migrate to Spring Social
we'll be depending on their API and some of the artifacts that are currently in use will be obsolete, however we've already
made sure that the impact of such migration is minimal by aligning our API with the current state (at the time of writing)
of Spring Social.

To get the text from the org.springframework.social.twitter.api.Tweet
simply invoke the getText() method.

27.5 Twitter Outbound Adapter

The current release of Spring Integration supports sending Status Update Messages and Direct Messages.
Twitter outbound channel adapters will take the Message payload and send it as a Twitter message. Currently the only supported payload type is
String, so consider adding a transformer if the payload of the incoming message is not a String.

27.5.1 Twitter Outbound Update Channel Adapter

This adapter allows you to send regular status updates by simply sending a Message to the channel
identified by the channel attribute.

The only extra configuration that is required for this adapter is the twitter-template reference.

When it comes to Twitter Direct Messages, you must specify who you are sending the message to - the target userid.
The Twitter Outbound Direct Message Channel Adapter will look for a target userid in the Message headers under the name
twitter_dmTargetUserId which is also identified by the following constant: TwitterHeaders.DM_TARGET_USER_ID.
So when creating a Message all you need to do is add a value for that header.

The above approach works well if you are creating the Message programmatically. However it's more common to
provide the header value within a messaging flow. The value can be provided by an upstream <header-enricher>.

Twitter does not allow you to post duplicate Messages. This is a common problem during testing when
the same code works the first time but does not work the second time. So, make sure to change the content of the Message
each time. Another thing that works well for testing is to append a timestamp to the end of each message.