Merge pull request #68 from olegz/INT-1818
using parameterized types migrated Twitter support to use Spring Social
This commit is contained in:
@@ -457,7 +457,8 @@ project('spring-integration-twitter') {
|
||||
dependencies {
|
||||
compile project(":spring-integration-core")
|
||||
compile "org.springframework:spring-context-support:$springVersion"
|
||||
compile "org.twitter4j:twitter4j-core:2.1.12"
|
||||
compile "org.springframework.social:spring-social-twitter:1.0.0.RELEASE"
|
||||
compile "org.springframework.security:spring-security-crypto:3.1.0.RC3"
|
||||
compile("javax.activation:activation:$javaxActivationVersion") { optional = true }
|
||||
testCompile project(":spring-integration-test")
|
||||
}
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
</para>
|
||||
<para>
|
||||
<important>
|
||||
Current Twitter support is based on the <link linkend="http://twitter4j.org/en/index.html">Twitter4J API</link>.
|
||||
However, future versions will be changed to use the <link linkend="https://jira.springframework.org/browse/SOCIAL">Spring Social</link>
|
||||
project as it is nearing its first release at the time of writing.
|
||||
Previous versions of Spring Integration were dependent upon the <link linkend="http://twitter4j.org/en/index.html">Twitter4J API</link>,
|
||||
but with the release of <link linkend="http://www.springsource.org/spring-social">Spring Social 1.0 GA</link>,
|
||||
Spring Integration, as of version 2.1, now builds directly upon Spring Social's Twitter support, instead of Twitter4J.
|
||||
</important>
|
||||
</para>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
the following within your XML header.
|
||||
<programlisting language="xml"><![CDATA[xmlns:int-twitter="http://www.springframework.org/schema/integration/twitter"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/integration/twitter
|
||||
http://www.springframework.org/schema/integration/twitter/spring-integration-twitter-2.0.xsd"]]></programlisting>
|
||||
http://www.springframework.org/schema/integration/twitter/spring-integration-twitter-2.1.xsd"]]></programlisting>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
@@ -72,15 +72,15 @@ xsi:schemaLocation="http://www.springframework.org/schema/integration/twitter
|
||||
<title>Twitter Template</title>
|
||||
|
||||
<para>
|
||||
Spring Integration uses the same familiar template pattern to interact with Twitter. Since current Twitter support
|
||||
is based on the Twitter4J API we provide a simple Twiter4JTemplate.
|
||||
For anonymous operations (e.g., search), you don't have to define <classname>Twitter4JTemplate</classname> explicitly, since a default
|
||||
instance will be created and injected into the endpoint. However, for authenticated operation
|
||||
(update status, send direct message, etc.), you must configure <classname>Twitter4JTemplate</classname> as a bean and
|
||||
inject it explicitly into the endpoint, because the authentication configuration is required.
|
||||
Below is a sample configuration of Twitter4JTemplate:
|
||||
|
||||
<programlisting language="xml"><![CDATA[<bean id="twitterTemplate" class="org.springframework.integration.twitter.core.Twitter4jTemplate">
|
||||
As mentioned above, Spring Integration relies upon Spring Social, and that library provides an implementation of the template
|
||||
pattern, <classname>org.springframework.social.twitter.api.impl.TwitterTemplate</classname> to interact with Twitter.
|
||||
For anonymous operations (e.g., search), you don't have to define an instance of <classname>TwitterTemplate</classname> 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 <classname>TwitterTemplate</classname> as a bean and
|
||||
inject it explicitly into the endpoint, because the authentication configuration is required.
|
||||
Below is a sample configuration of TwitterTemplate:
|
||||
|
||||
<programlisting language="xml"><![CDATA[<bean id="twitterTemplate" class="org.springframework.social.twitter.api.impl.TwitterTemplate">
|
||||
<constructor-arg value="4XzBPacJQxyBzzzH"/>
|
||||
<constructor-arg value="AbRxUAvyCtqQtvxFK8w5ZMtMj20KFhB6o"/>
|
||||
<constructor-arg value="21691649-4YZY5iJEOfz2A9qCFd9SjBRGb3HLmIm4HNE"/>
|
||||
@@ -108,7 +108,7 @@ twitter.oauth.accessTokenSecret=AbRxUAvyNCtqQtxFK8w5ZMtMj20KFhB6o]]></programlis
|
||||
<programlisting language="java"><![CDATA[<context:property-placeholder
|
||||
location="classpath:oauth.properties"/>
|
||||
|
||||
<bean id="twitterTemplate" class="org.springframework.integration.twitter.core.Twitter4jTemplate">
|
||||
<bean id="twitterTemplate" class="org.springframework.social.twitter.api.impl.TwitterTemplate">
|
||||
<constructor-arg value="${twitter.oauth.consumerKey}"/>
|
||||
<constructor-arg value="${twitter.oauth.consumerSecret}"/>
|
||||
<constructor-arg value="${twitter.oauth.accessToken}"/>
|
||||
@@ -219,7 +219,7 @@ received.
|
||||
of Spring Social.
|
||||
</para>
|
||||
<para>
|
||||
To get the text from the <classname>org.springframework.integration.twitter.core.Tweet</classname>
|
||||
To get the text from the <classname>org.springframework.social.twitter.api.Tweet</classname>
|
||||
simply invoke the <code>getText()</code> method.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors
|
||||
* Copyright 2002-2011 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.
|
||||
@@ -23,6 +23,11 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.config.xml.AbstractPollingInboundChannelAdapterParser;
|
||||
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
|
||||
import org.springframework.integration.twitter.inbound.DirectMessageReceivingMessageSource;
|
||||
import org.springframework.integration.twitter.inbound.MentionsReceivingMessageSource;
|
||||
import org.springframework.integration.twitter.inbound.SearchReceivingMessageSource;
|
||||
import org.springframework.integration.twitter.inbound.TimelineReceivingMessageSource;
|
||||
import org.springframework.social.twitter.api.impl.TwitterTemplate;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -33,20 +38,16 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public class TwitterInboundChannelAdapterParser extends AbstractPollingInboundChannelAdapterParser {
|
||||
|
||||
private static final String BASE_PACKAGE = "org.springframework.integration.twitter";
|
||||
|
||||
|
||||
@Override
|
||||
protected BeanMetadataElement parseSource(Element element, ParserContext parserContext) {
|
||||
String className = determineClassName(element, parserContext);
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(className);
|
||||
Class<?> clazz = determineClass(element, parserContext);
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(clazz);
|
||||
String templateBeanName = element.getAttribute("twitter-template");
|
||||
if (StringUtils.hasText(templateBeanName)) {
|
||||
builder.addConstructorArgReference(templateBeanName);
|
||||
}
|
||||
else {
|
||||
BeanDefinitionBuilder templateBuilder = BeanDefinitionBuilder.genericBeanDefinition(
|
||||
BASE_PACKAGE + ".core.Twitter4jTemplate");
|
||||
BeanDefinitionBuilder templateBuilder = BeanDefinitionBuilder.genericBeanDefinition(TwitterTemplate.class);
|
||||
builder.addConstructorArgValue(templateBuilder.getBeanDefinition());
|
||||
}
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "query");
|
||||
@@ -54,25 +55,25 @@ public class TwitterInboundChannelAdapterParser extends AbstractPollingInboundCh
|
||||
}
|
||||
|
||||
|
||||
private static String determineClassName(Element element, ParserContext parserContext) {
|
||||
String className = null;
|
||||
private static Class<?> determineClass(Element element, ParserContext parserContext) {
|
||||
Class<?> clazz = null;
|
||||
String elementName = element.getLocalName().trim();
|
||||
if ("inbound-channel-adapter".equals(elementName)) {
|
||||
className = BASE_PACKAGE + ".inbound.TimelineReceivingMessageSource";
|
||||
clazz = TimelineReceivingMessageSource.class;
|
||||
}
|
||||
else if ("dm-inbound-channel-adapter".equals(elementName)) {
|
||||
className = BASE_PACKAGE + ".inbound.DirectMessageReceivingMessageSource";
|
||||
clazz = DirectMessageReceivingMessageSource.class;
|
||||
}
|
||||
else if ("mentions-inbound-channel-adapter".equals(elementName)) {
|
||||
className = BASE_PACKAGE + ".inbound.MentionsReceivingMessageSource";
|
||||
clazz = MentionsReceivingMessageSource.class;
|
||||
}
|
||||
else if ("search-inbound-channel-adapter".equals(elementName)){
|
||||
className = BASE_PACKAGE + ".inbound.SearchReceivingMessageSource";
|
||||
clazz = SearchReceivingMessageSource.class;
|
||||
}
|
||||
else {
|
||||
parserContext.getReaderContext().error("element '" + elementName + "' is not supported by this parser.", element);
|
||||
}
|
||||
return className;
|
||||
return clazz;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors
|
||||
* Copyright 2002-2011 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors
|
||||
* Copyright 2002-2011 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.
|
||||
@@ -22,6 +22,8 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.config.xml.AbstractOutboundChannelAdapterParser;
|
||||
import org.springframework.integration.twitter.outbound.DirectMessageSendingMessageHandler;
|
||||
import org.springframework.integration.twitter.outbound.StatusUpdatingMessageHandler;
|
||||
|
||||
/**
|
||||
* Parser for all outbound Twitter adapters
|
||||
@@ -32,31 +34,28 @@ import org.springframework.integration.config.xml.AbstractOutboundChannelAdapter
|
||||
*/
|
||||
public class TwitterOutboundChannelAdapterParser extends AbstractOutboundChannelAdapterParser {
|
||||
|
||||
private static final String BASE_PACKAGE = "org.springframework.integration.twitter";
|
||||
|
||||
|
||||
@Override
|
||||
protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) {
|
||||
String className = determineClassName(element, parserContext);
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(className);
|
||||
Class<?> clazz = determineClass(element, parserContext);
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(clazz);
|
||||
builder.addConstructorArgReference(element.getAttribute("twitter-template"));
|
||||
return builder.getBeanDefinition();
|
||||
}
|
||||
|
||||
|
||||
private static String determineClassName(Element element, ParserContext parserContext) {
|
||||
String className = null;
|
||||
private static Class<?> determineClass(Element element, ParserContext parserContext) {
|
||||
Class<?> clazz = null;
|
||||
String elementName = element.getLocalName().trim();
|
||||
if ("outbound-channel-adapter".equals(elementName)) {
|
||||
className = BASE_PACKAGE + ".outbound.StatusUpdatingMessageHandler";
|
||||
clazz = StatusUpdatingMessageHandler.class;
|
||||
}
|
||||
else if ("dm-outbound-channel-adapter".equals(elementName)) {
|
||||
className = BASE_PACKAGE + ".outbound.DirectMessageSendingMessageHandler";
|
||||
clazz = DirectMessageSendingMessageHandler.class;
|
||||
}
|
||||
else {
|
||||
parserContext.getReaderContext().error("element '" + elementName + "' is not supported by this parser.", element);
|
||||
}
|
||||
return className;
|
||||
return clazz;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* 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.twitter.core;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents the results of a Twitter search, including matching {@link Tweet}s
|
||||
* and any metadata associated with that search.
|
||||
*
|
||||
* @author Craig Walls
|
||||
*/
|
||||
public class SearchResults {
|
||||
|
||||
private List<Tweet> tweets;
|
||||
|
||||
private long maxId;
|
||||
|
||||
private long sinceId;
|
||||
|
||||
|
||||
public SearchResults(List<Tweet> tweets, long maxId, long sinceId) {
|
||||
this.tweets = tweets;
|
||||
this.maxId = maxId;
|
||||
this.sinceId = sinceId;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the list of matching {@link Tweet}s
|
||||
*/
|
||||
public List<Tweet> getTweets() {
|
||||
return tweets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum {@link Tweet} ID in the search results
|
||||
*/
|
||||
public long getMaxId() {
|
||||
return maxId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Tweet} ID after which all of the matching {@link Tweet}s were created
|
||||
*/
|
||||
public long getSinceId() {
|
||||
return sinceId;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
/*
|
||||
* 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.twitter.core;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Represents a Twitter status update (e.g., a "tweet").
|
||||
*
|
||||
* @author Craig Walls
|
||||
* @author Oleg Zhurakousky
|
||||
*/
|
||||
public class Tweet {
|
||||
|
||||
private long id;
|
||||
|
||||
private String text;
|
||||
|
||||
private Date createdAt;
|
||||
|
||||
private String fromUser;
|
||||
|
||||
private String profileImageUrl;
|
||||
|
||||
private Long toUserId;
|
||||
|
||||
private long fromUserId;
|
||||
|
||||
private String languageCode;
|
||||
|
||||
private String source;
|
||||
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public Date getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public void setCreatedAt(Date createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
public String getFromUser() {
|
||||
return fromUser;
|
||||
}
|
||||
|
||||
public void setFromUser(String fromUser) {
|
||||
this.fromUser = fromUser;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getProfileImageUrl() {
|
||||
return profileImageUrl;
|
||||
}
|
||||
|
||||
public void setProfileImageUrl(String profileImageUrl) {
|
||||
this.profileImageUrl = profileImageUrl;
|
||||
}
|
||||
|
||||
public Long getToUserId() {
|
||||
return toUserId;
|
||||
}
|
||||
|
||||
public void setToUserId(Long toUserId) {
|
||||
this.toUserId = toUserId;
|
||||
}
|
||||
|
||||
public long getFromUserId() {
|
||||
return fromUserId;
|
||||
}
|
||||
|
||||
public void setFromUserId(long fromUserId) {
|
||||
this.fromUserId = fromUserId;
|
||||
}
|
||||
|
||||
public String getLanguageCode() {
|
||||
return languageCode;
|
||||
}
|
||||
|
||||
public void setLanguageCode(String languageCode) {
|
||||
this.languageCode = languageCode;
|
||||
}
|
||||
|
||||
public String getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
public void setSource(String source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,287 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.twitter.core;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import twitter4j.DirectMessage;
|
||||
import twitter4j.Paging;
|
||||
import twitter4j.Query;
|
||||
import twitter4j.QueryResult;
|
||||
import twitter4j.ResponseList;
|
||||
import twitter4j.Status;
|
||||
import twitter4j.StatusUpdate;
|
||||
import twitter4j.Twitter;
|
||||
import twitter4j.TwitterFactory;
|
||||
import twitter4j.http.AccessToken;
|
||||
|
||||
/**
|
||||
* Implementation of {@link TwitterOperations} that delegates to Twitter4J.
|
||||
*
|
||||
* @author Oleg Zhurakousky
|
||||
* @since 2.0
|
||||
*/
|
||||
public class Twitter4jTemplate implements TwitterOperations {
|
||||
|
||||
private final Twitter twitter;
|
||||
|
||||
|
||||
/**
|
||||
* Used to construct this template to perform Twitter API calls that do not require authorization.
|
||||
* (e.g., search)
|
||||
*/
|
||||
public Twitter4jTemplate() {
|
||||
this.twitter = new TwitterFactory().getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to construct this template with OAuth authentication/authorization to perform Twitter API calls
|
||||
* that do require authorization (e.g., send/receive DirectMessage)
|
||||
*
|
||||
* @param consumerKey
|
||||
* @param consumerSecret
|
||||
* @param accessToken
|
||||
* @param accessTokenSecret
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public Twitter4jTemplate(String consumerKey, String consumerSecret, String accessToken, String accessTokenSecret) {
|
||||
Assert.hasText(consumerKey, "'consumerKey' must be provided");
|
||||
Assert.hasText(consumerSecret, "'consumerSecret' must be provided");
|
||||
Assert.hasText(accessToken, "'accessToken' must be provided");
|
||||
Assert.hasText(accessTokenSecret, "'accessTokenSecret' must be provided");
|
||||
|
||||
AccessToken token = new AccessToken(accessToken, accessTokenSecret);
|
||||
this.twitter = new TwitterFactory().getOAuthAuthorizedInstance(consumerKey, consumerSecret, token);
|
||||
/*
|
||||
* We are aware of the fact that the above method is deprecated and the code should really look
|
||||
* like the one below, but we are keeping the deprecated call to address backwards compatibility.
|
||||
* In future versions we won't be relying on Twitter4J in favor of SpringSocial API.
|
||||
*/
|
||||
// Properties properties = new Properties();
|
||||
// properties.put("oauth.consumerKey", consumerKey);
|
||||
// properties.put("oauth.consumerSecret", consumerSecret);
|
||||
// Configuration configuration = new PropertyConfiguration(properties);
|
||||
// this.twitter = new TwitterFactory(configuration).getInstance(token);
|
||||
}
|
||||
|
||||
|
||||
public String getProfileId() {
|
||||
try {
|
||||
if (twitter.isOAuthEnabled()) {
|
||||
return twitter.getScreenName();
|
||||
}
|
||||
else {
|
||||
return "twitter-anonymous";
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new TwitterOperationException("Failed to obtain Profile ID. ", e);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Tweet> getDirectMessages() {
|
||||
try {
|
||||
ResponseList<DirectMessage> directMessages = twitter.getDirectMessages();
|
||||
return this.buildTweetsFromTwitterResponses(directMessages);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new TwitterOperationException("Failed to receive Direct Messages. ", e);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Tweet> getDirectMessages(long sinceId) {
|
||||
try {
|
||||
ResponseList<DirectMessage> directMessages = twitter.getDirectMessages(new Paging(sinceId));
|
||||
return this.buildTweetsFromTwitterResponses(directMessages);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new TwitterOperationException("Failed to receive Direct Messages since the last message with ID: "
|
||||
+ sinceId + ".", e);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Tweet> getMentions() {
|
||||
try {
|
||||
ResponseList<Status> mentions = twitter.getMentions();
|
||||
return this.buildTweetsFromTwitterResponses(mentions);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new TwitterOperationException("Failed to receive Mention statuses. ", e);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Tweet> getMentions(long sinceId) {
|
||||
try {
|
||||
ResponseList<Status> mentions = twitter.getMentions(new Paging(sinceId));
|
||||
return this.buildTweetsFromTwitterResponses(mentions);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new TwitterOperationException("Failed to receive Mention statuses since the last status with ID: "
|
||||
+ sinceId + ".", e);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Tweet> getTimeline() {
|
||||
try {
|
||||
ResponseList<Status> timelines = twitter.getHomeTimeline();
|
||||
return this.buildTweetsFromTwitterResponses(timelines);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new TwitterOperationException("Failed to receive Timeline statuses. ", e);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Tweet> getTimeline(long sinceId) {
|
||||
try {
|
||||
ResponseList<Status> timelines = twitter.getHomeTimeline(new Paging(sinceId));
|
||||
return this.buildTweetsFromTwitterResponses(timelines);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new TwitterOperationException("Failed to receive Timeline statuses since the last status with ID: "
|
||||
+ sinceId + ".", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendDirectMessage(String userName, String text) {
|
||||
Assert.hasText(userName, "'userName' is required");
|
||||
Assert.hasText(text, "'text' is required");
|
||||
try {
|
||||
twitter.sendDirectMessage(userName, text);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new TwitterOperationException("Failed to send Direct Message to user: " + userName + ".", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendDirectMessage(int userId, String text) {
|
||||
Assert.state(userId > 0, "'userId' is required");
|
||||
Assert.hasText(text, "'text' is required");
|
||||
try {
|
||||
twitter.sendDirectMessage(userId, text);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new TwitterOperationException("Failed to send Direct Message to user with id: " + userId + ".", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateStatus(String statusTweet) {
|
||||
Assert.hasText(statusTweet, "'statusTweet' must not be null");
|
||||
try {
|
||||
StatusUpdate status = new StatusUpdate(statusTweet);
|
||||
twitter.updateStatus(status);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new TwitterOperationException("Failed to send Status update. ", e);
|
||||
}
|
||||
}
|
||||
|
||||
public SearchResults search(String query) {
|
||||
Assert.hasText(query, "'query' must not be null");
|
||||
Query q = new Query(query);
|
||||
return this.search(q);
|
||||
}
|
||||
|
||||
public SearchResults search(String query, long sinceId) {
|
||||
Assert.hasText(query, "'query' must not be null");
|
||||
Query q = new Query(query);
|
||||
q.setSinceId(sinceId);
|
||||
return this.search(q);
|
||||
}
|
||||
|
||||
public Twitter getUnderlyingTwitter() {
|
||||
return this.twitter;
|
||||
}
|
||||
|
||||
|
||||
private SearchResults search(Query query) {
|
||||
try {
|
||||
QueryResult result = twitter.search(query);
|
||||
if (result != null) {
|
||||
List<twitter4j.Tweet> t4jTweets = result.getTweets();
|
||||
List<Tweet> tweets = this.buildTweetsFromTwitterResponses(t4jTweets);
|
||||
SearchResults results = new SearchResults(tweets, result.getMaxId(), result.getSinceId());
|
||||
return results;
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new TwitterOperationException("failed to perform Twitter search", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<Tweet> buildTweetsFromTwitterResponses(List<?> responses) {
|
||||
List<Tweet> tweets = new LinkedList<Tweet>();
|
||||
if (responses != null) {
|
||||
for (Object response : responses) {
|
||||
if (response instanceof Status) {
|
||||
tweets.add(this.buildTweetFromStatus((Status) response));
|
||||
}
|
||||
else if (response instanceof DirectMessage) {
|
||||
tweets.add(this.buildTweetFromDm((DirectMessage) response));
|
||||
}
|
||||
else if (response instanceof twitter4j.Tweet) {
|
||||
tweets.add(this.buildTweetFromTwitter4jTweet((twitter4j.Tweet) response));
|
||||
}
|
||||
else {
|
||||
throw new TwitterOperationException("Unsupported response type: " + response.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
return tweets;
|
||||
}
|
||||
|
||||
private Tweet buildTweetFromDm(DirectMessage dm) {
|
||||
Tweet tweet = new Tweet();
|
||||
tweet.setCreatedAt(dm.getCreatedAt());
|
||||
tweet.setFromUser(dm.getSenderScreenName());
|
||||
tweet.setFromUserId(dm.getSenderId());
|
||||
tweet.setId(dm.getId());
|
||||
tweet.setText(dm.getText());
|
||||
tweet.setToUserId((long)dm.getRecipientId());
|
||||
return tweet;
|
||||
}
|
||||
|
||||
private Tweet buildTweetFromStatus(Status status) {
|
||||
Tweet tweet = new Tweet();
|
||||
tweet.setCreatedAt(status.getCreatedAt());
|
||||
if (status.getUser() != null){
|
||||
tweet.setFromUser(status.getUser().getScreenName());
|
||||
tweet.setFromUserId(status.getUser().getId());
|
||||
}
|
||||
tweet.setId(status.getId());
|
||||
tweet.setSource(status.getSource());
|
||||
tweet.setText(status.getText());
|
||||
return tweet;
|
||||
}
|
||||
|
||||
private Tweet buildTweetFromTwitter4jTweet(twitter4j.Tweet t4jTweet) {
|
||||
Tweet tweet = new Tweet();
|
||||
tweet.setCreatedAt(t4jTweet.getCreatedAt());
|
||||
tweet.setFromUser(t4jTweet.getFromUser());
|
||||
tweet.setFromUserId(t4jTweet.getFromUserId());
|
||||
tweet.setId(t4jTweet.getId());
|
||||
tweet.setLanguageCode(t4jTweet.getIsoLanguageCode());
|
||||
tweet.setProfileImageUrl(t4jTweet.getProfileImageUrl());
|
||||
tweet.setSource(t4jTweet.getSource());
|
||||
tweet.setText(t4jTweet.getText());
|
||||
return tweet;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
* 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.twitter.core;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import twitter4j.TwitterException;
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
* @since 2.0
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class TwitterOperationException extends RuntimeException {
|
||||
|
||||
private int twitterStatusCode = -1;
|
||||
|
||||
|
||||
public TwitterOperationException() {
|
||||
this(null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param description
|
||||
*/
|
||||
public TwitterOperationException(String description) {
|
||||
this(description, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param throwable
|
||||
*/
|
||||
public TwitterOperationException(Throwable throwable) {
|
||||
this(null, throwable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param description
|
||||
* @param throwable
|
||||
*/
|
||||
public TwitterOperationException(String description, Throwable throwable) {
|
||||
super(formatDescription(description, throwable), throwable);
|
||||
if (throwable instanceof TwitterException){
|
||||
this.twitterStatusCode = ((TwitterException)throwable).getStatusCode();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public int getTwitterStatusCode() {
|
||||
return twitterStatusCode;
|
||||
}
|
||||
|
||||
|
||||
private static String formatDescription(String description, Throwable throwable) {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
if (StringUtils.hasText(description)){
|
||||
buffer.append(description + " ");
|
||||
}
|
||||
if (throwable != null && throwable instanceof TwitterException){
|
||||
TwitterException te = (TwitterException) throwable;
|
||||
String message = te.getMessage();
|
||||
if (StringUtils.hasText(message)) {
|
||||
buffer.append("Detailed Error: ");
|
||||
if (message.contains("{")){
|
||||
buffer.append(message.substring(0, message.indexOf("{")));
|
||||
}
|
||||
else {
|
||||
buffer.append(message);
|
||||
}
|
||||
}
|
||||
buffer.append("For more information about this exception please visit the following Twitter website: " +
|
||||
"http://apiwiki.twitter.com/w/page/22554652/HTTP-Response-Codes-and-Errors");
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
* 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.twitter.core;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import twitter4j.Twitter;
|
||||
|
||||
/**
|
||||
* @author Craig Walls
|
||||
* @author Oleg Zhurakousky
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface TwitterOperations {
|
||||
|
||||
/**
|
||||
* Retrieves the user's Twitter screen name.
|
||||
*
|
||||
* @return the user's screen name at Twitter
|
||||
*/
|
||||
String getProfileId();
|
||||
|
||||
/**
|
||||
* Updates the user's status.
|
||||
*
|
||||
* @param status
|
||||
* The status message
|
||||
*
|
||||
*/
|
||||
void updateStatus(String status);
|
||||
|
||||
/**
|
||||
* Searches Twitter, returning the first page of {@link Tweet}s
|
||||
*
|
||||
* @param query
|
||||
* The search query string
|
||||
* @return a {@link SearchResults} containing {@link Tweet}s
|
||||
*
|
||||
*/
|
||||
SearchResults search(String query);
|
||||
|
||||
/**
|
||||
* Searches Twitter, returning a specific page out of the complete set of
|
||||
* results.
|
||||
*
|
||||
* @param query
|
||||
* The search query string
|
||||
* @param sinceId
|
||||
* The minimum {@link Tweet} ID to return in the results
|
||||
*
|
||||
* @return a {@link SearchResults} containing {@link Tweet}s
|
||||
*
|
||||
*/
|
||||
SearchResults search(String query, long sinceId);
|
||||
|
||||
List<Tweet> getDirectMessages();
|
||||
|
||||
List<Tweet> getDirectMessages(long sinceId);
|
||||
|
||||
List<Tweet> getMentions();
|
||||
|
||||
List<Tweet> getMentions(long sinceId);
|
||||
|
||||
List<Tweet> getTimeline();
|
||||
|
||||
List<Tweet> getTimeline(long sinceId);
|
||||
|
||||
void sendDirectMessage(String userName, String text);
|
||||
|
||||
void sendDirectMessage(int userId, String text);
|
||||
|
||||
/**
|
||||
* Temporary method. Should be removed one migrated to Spring Social
|
||||
*/
|
||||
Twitter getUnderlyingTwitter();
|
||||
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
/* Copyright 2002-2011 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.
|
||||
@@ -18,6 +17,7 @@ package org.springframework.integration.twitter.inbound;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
@@ -31,8 +31,10 @@ import org.springframework.integration.core.MessageSource;
|
||||
import org.springframework.integration.store.MetadataStore;
|
||||
import org.springframework.integration.store.SimpleMetadataStore;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.integration.twitter.core.Tweet;
|
||||
import org.springframework.integration.twitter.core.TwitterOperations;
|
||||
import org.springframework.social.twitter.api.DirectMessage;
|
||||
import org.springframework.social.twitter.api.Tweet;
|
||||
import org.springframework.social.twitter.api.Twitter;
|
||||
import org.springframework.social.twitter.api.UserOperations;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -58,7 +60,7 @@ abstract class AbstractTwitterMessageSource<T> extends IntegrationObjectSupport
|
||||
|
||||
private volatile String metadataKey;
|
||||
|
||||
private final Queue<Tweet> tweets = new LinkedBlockingQueue<Tweet>();
|
||||
private final Queue<T> tweets = new LinkedBlockingQueue<T>();
|
||||
|
||||
private volatile int prefetchThreshold = 0;
|
||||
|
||||
@@ -66,21 +68,21 @@ abstract class AbstractTwitterMessageSource<T> extends IntegrationObjectSupport
|
||||
|
||||
private volatile long lastProcessedId = -1;
|
||||
|
||||
private final TwitterOperations twitterOperations;
|
||||
private final Twitter twitter;
|
||||
|
||||
private final TweetComparator tweetComparator = new TweetComparator();
|
||||
|
||||
private final Object lastEnqueuedIdMonitor = new Object();
|
||||
|
||||
|
||||
public AbstractTwitterMessageSource(TwitterOperations twitterOperations) {
|
||||
Assert.notNull(twitterOperations, "twitterOperations must not be null");
|
||||
this.twitterOperations = twitterOperations;
|
||||
public AbstractTwitterMessageSource(Twitter twitter) {
|
||||
Assert.notNull(twitter, "twitter must not be null");
|
||||
this.twitter = twitter;
|
||||
}
|
||||
|
||||
|
||||
protected TwitterOperations getTwitterOperations() {
|
||||
return this.twitterOperations;
|
||||
protected Twitter getTwitter() {
|
||||
return this.twitter;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -106,21 +108,26 @@ abstract class AbstractTwitterMessageSource<T> extends IntegrationObjectSupport
|
||||
else if (logger.isWarnEnabled()) {
|
||||
logger.warn(this.getClass().getSimpleName() + " has no name. MetadataStore key might not be unique.");
|
||||
}
|
||||
String profileId = this.twitterOperations.getProfileId();
|
||||
if (profileId != null) {
|
||||
metadataKeyBuilder.append(profileId);
|
||||
}
|
||||
this.metadataKey = metadataKeyBuilder.toString();
|
||||
String lastId = this.metadataStore.get(this.metadataKey);
|
||||
// initialize the last status ID from the metadataStore
|
||||
if (StringUtils.hasText(lastId)) {
|
||||
this.lastProcessedId = Long.parseLong(lastId);
|
||||
this.lastEnqueuedId = this.lastProcessedId;
|
||||
|
||||
UserOperations userOperations = this.twitter.userOperations();
|
||||
if (userOperations != null){
|
||||
String profileId = String.valueOf(userOperations.getProfileId());
|
||||
if (profileId != null) {
|
||||
metadataKeyBuilder.append(profileId);
|
||||
}
|
||||
this.metadataKey = metadataKeyBuilder.toString();
|
||||
String lastId = this.metadataStore.get(this.metadataKey);
|
||||
// initialize the last status ID from the metadataStore
|
||||
if (StringUtils.hasText(lastId)) {
|
||||
this.lastProcessedId = Long.parseLong(lastId);
|
||||
this.lastEnqueuedId = this.lastProcessedId;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Message<?> receive() {
|
||||
Tweet tweet = this.tweets.poll();
|
||||
T tweet = this.tweets.poll();
|
||||
if (tweet == null) {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
long elapsedTime = currentTime - this.lastPollForTweet;
|
||||
@@ -133,23 +140,23 @@ abstract class AbstractTwitterMessageSource<T> extends IntegrationObjectSupport
|
||||
this.lastPollForTweet = currentTime;
|
||||
}
|
||||
if (tweet != null) {
|
||||
this.lastProcessedId = tweet.getId();
|
||||
this.lastProcessedId = this.getIdForTweet(tweet);
|
||||
this.metadataStore.put(this.metadataKey, String.valueOf(this.lastProcessedId));
|
||||
return MessageBuilder.withPayload(tweet).build();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void enqueueAll(List<Tweet> tweets) {
|
||||
private void enqueueAll(List<T> tweets) {
|
||||
Collections.sort(tweets, this.tweetComparator);
|
||||
for (Tweet tweet : tweets) {
|
||||
for (T tweet : tweets) {
|
||||
enqueue(tweet);
|
||||
}
|
||||
}
|
||||
|
||||
private void enqueue(Tweet tweet) {
|
||||
private void enqueue(T tweet) {
|
||||
synchronized (this.lastEnqueuedIdMonitor) {
|
||||
long id = tweet.getId();
|
||||
long id = this.getIdForTweet(tweet);
|
||||
if (id > this.lastEnqueuedId) {
|
||||
this.tweets.add(tweet);
|
||||
this.lastEnqueuedId = id;
|
||||
@@ -160,7 +167,7 @@ abstract class AbstractTwitterMessageSource<T> extends IntegrationObjectSupport
|
||||
private void refreshTweetQueueIfNecessary() {
|
||||
try {
|
||||
if (tweets.size() <= prefetchThreshold) {
|
||||
List<Tweet> tweets = pollForTweets(lastEnqueuedId);
|
||||
List<T> tweets = pollForTweets(lastEnqueuedId);
|
||||
if (!CollectionUtils.isEmpty(tweets)) {
|
||||
enqueueAll(tweets);
|
||||
}
|
||||
@@ -178,13 +185,47 @@ abstract class AbstractTwitterMessageSource<T> extends IntegrationObjectSupport
|
||||
* Subclasses must implement this to return tweets.
|
||||
* The 'sinceId' value will be negative if no last id is known.
|
||||
*/
|
||||
protected abstract List<Tweet> pollForTweets(long sinceId);
|
||||
protected abstract List<T> pollForTweets(long sinceId);
|
||||
|
||||
|
||||
private static class TweetComparator implements Comparator<Tweet> {
|
||||
private long getIdForTweet(T twitterMessage) {
|
||||
if (twitterMessage instanceof Tweet) {
|
||||
return ((Tweet) twitterMessage).getId();
|
||||
}
|
||||
else if (twitterMessage instanceof DirectMessage) {
|
||||
return ((DirectMessage) twitterMessage).getId();
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Unsupported Twitter object: " + twitterMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public int compare(Tweet tweet1, Tweet tweet2) {
|
||||
return tweet1.getCreatedAt().compareTo(tweet2.getCreatedAt());
|
||||
|
||||
private class TweetComparator implements Comparator<T> {
|
||||
|
||||
public int compare(T tweet1, T tweet2) {
|
||||
// hopefully temporary logic. Will suggest that SpringSocial use a common base class for DM and Tweet
|
||||
if (tweet1 instanceof Tweet && tweet2 instanceof Tweet) {
|
||||
Tweet t1 = (Tweet) tweet1;
|
||||
Tweet t2 = (Tweet) tweet2;
|
||||
Date t1CreatedAt = t1.getCreatedAt();
|
||||
Date t2CreatedAt = t2.getCreatedAt();
|
||||
Assert.notNull(t1CreatedAt, "Tweet is missing 'createdAt' date. Cannot compare.");
|
||||
Assert.notNull(t2CreatedAt, "Tweet is missing 'createdAt' date. Cannot compare.");
|
||||
return t1CreatedAt.compareTo(t2CreatedAt);
|
||||
}
|
||||
else if (tweet1 instanceof DirectMessage && tweet2 instanceof DirectMessage) {
|
||||
DirectMessage d1 = (DirectMessage) tweet1;
|
||||
DirectMessage d2 = (DirectMessage) tweet2;
|
||||
Date d1CreatedAt = d1.getCreatedAt();
|
||||
Date d2CreatedAt = d2.getCreatedAt();
|
||||
Assert.notNull(d1CreatedAt, "DirectMessage is missing 'createdAt' date. Cannot compare.");
|
||||
Assert.notNull(d2CreatedAt, "DirectMessage is missing 'createdAt' date. Cannot compare.");
|
||||
return d1CreatedAt.compareTo(d2CreatedAt);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Uncomparable Twitter objects: " + tweet1 + " and " + tweet2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 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.
|
||||
@@ -18,8 +18,8 @@ package org.springframework.integration.twitter.inbound;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.integration.twitter.core.Tweet;
|
||||
import org.springframework.integration.twitter.core.TwitterOperations;
|
||||
import org.springframework.social.twitter.api.DirectMessage;
|
||||
import org.springframework.social.twitter.api.Twitter;
|
||||
|
||||
/**
|
||||
* This class handles support for receiving DMs (direct messages) using Twitter.
|
||||
@@ -29,9 +29,9 @@ import org.springframework.integration.twitter.core.TwitterOperations;
|
||||
* @author Mark Fisher
|
||||
* @since 2.0
|
||||
*/
|
||||
public class DirectMessageReceivingMessageSource extends AbstractTwitterMessageSource<Tweet> {
|
||||
public class DirectMessageReceivingMessageSource extends AbstractTwitterMessageSource<DirectMessage> {
|
||||
|
||||
public DirectMessageReceivingMessageSource(TwitterOperations twitter) {
|
||||
public DirectMessageReceivingMessageSource(Twitter twitter) {
|
||||
super(twitter);
|
||||
}
|
||||
|
||||
@@ -42,10 +42,8 @@ public class DirectMessageReceivingMessageSource extends AbstractTwitterMessageS
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Tweet> pollForTweets(long sinceId) {
|
||||
return (sinceId > 0)
|
||||
? this.getTwitterOperations().getDirectMessages(sinceId)
|
||||
: this.getTwitterOperations().getDirectMessages();
|
||||
protected List<DirectMessage> pollForTweets(long sinceId) {
|
||||
return this.getTwitter().directMessageOperations().getDirectMessagesReceived(1, 20, sinceId, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 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.
|
||||
@@ -18,8 +18,8 @@ package org.springframework.integration.twitter.inbound;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.integration.twitter.core.Tweet;
|
||||
import org.springframework.integration.twitter.core.TwitterOperations;
|
||||
import org.springframework.social.twitter.api.Tweet;
|
||||
import org.springframework.social.twitter.api.Twitter;
|
||||
|
||||
/**
|
||||
* Handles forwarding all new {@link twitter4j.Status} that are 'replies' or 'mentions' to some other tweet.
|
||||
@@ -30,19 +30,19 @@ import org.springframework.integration.twitter.core.TwitterOperations;
|
||||
*/
|
||||
public class MentionsReceivingMessageSource extends AbstractTwitterMessageSource<Tweet> {
|
||||
|
||||
public MentionsReceivingMessageSource(TwitterOperations twitter){
|
||||
public MentionsReceivingMessageSource(Twitter twitter) {
|
||||
super(twitter);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getComponentType() {
|
||||
return "twitter:mention-inbound-channel-adapter";
|
||||
return "twitter:mentions-inbound-channel-adapter";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Tweet> pollForTweets(long sinceId) {
|
||||
return (sinceId > 0) ? this.getTwitterOperations().getMentions(sinceId) : this.getTwitterOperations().getMentions();
|
||||
return this.getTwitter().timelineOperations().getMentions(1, 20, sinceId, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 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.
|
||||
@@ -16,11 +16,12 @@
|
||||
|
||||
package org.springframework.integration.twitter.inbound;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.integration.twitter.core.SearchResults;
|
||||
import org.springframework.integration.twitter.core.Tweet;
|
||||
import org.springframework.integration.twitter.core.TwitterOperations;
|
||||
import org.springframework.social.twitter.api.SearchResults;
|
||||
import org.springframework.social.twitter.api.Tweet;
|
||||
import org.springframework.social.twitter.api.Twitter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -33,7 +34,7 @@ public class SearchReceivingMessageSource extends AbstractTwitterMessageSource<T
|
||||
private volatile String query;
|
||||
|
||||
|
||||
public SearchReceivingMessageSource(TwitterOperations twitter) {
|
||||
public SearchReceivingMessageSource(Twitter twitter) {
|
||||
super(twitter);
|
||||
}
|
||||
|
||||
@@ -50,10 +51,8 @@ public class SearchReceivingMessageSource extends AbstractTwitterMessageSource<T
|
||||
|
||||
@Override
|
||||
protected List<Tweet> pollForTweets(long sinceId) {
|
||||
SearchResults results = (sinceId > 0)
|
||||
? this.getTwitterOperations().search(query, sinceId)
|
||||
: this.getTwitterOperations().search(query);
|
||||
return (results != null) ? results.getTweets() : null;
|
||||
SearchResults results = this.getTwitter().searchOperations().search(query, 1, 20, sinceId, 0);
|
||||
return (results != null) ? results.getTweets() : Collections.<Tweet>emptyList();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 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.
|
||||
@@ -18,8 +18,8 @@ package org.springframework.integration.twitter.inbound;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.integration.twitter.core.Tweet;
|
||||
import org.springframework.integration.twitter.core.TwitterOperations;
|
||||
import org.springframework.social.twitter.api.Tweet;
|
||||
import org.springframework.social.twitter.api.Twitter;
|
||||
|
||||
/**
|
||||
* This {@link org.springframework.integration.core.MessageSource} lets Spring Integration consume
|
||||
@@ -31,7 +31,7 @@ import org.springframework.integration.twitter.core.TwitterOperations;
|
||||
*/
|
||||
public class TimelineReceivingMessageSource extends AbstractTwitterMessageSource<Tweet> {
|
||||
|
||||
public TimelineReceivingMessageSource(TwitterOperations twitter){
|
||||
public TimelineReceivingMessageSource(Twitter twitter) {
|
||||
super(twitter);
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ public class TimelineReceivingMessageSource extends AbstractTwitterMessageSource
|
||||
|
||||
@Override
|
||||
protected List<Tweet> pollForTweets(long sinceId) {
|
||||
return(sinceId > 0) ? this.getTwitterOperations().getTimeline(sinceId) : this.getTwitterOperations().getTimeline();
|
||||
return this.getTwitter().timelineOperations().getHomeTimeline(1, 20, sinceId, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors
|
||||
* Copyright 2002-2011 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.
|
||||
@@ -19,7 +19,7 @@ package org.springframework.integration.twitter.outbound;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.handler.AbstractMessageHandler;
|
||||
import org.springframework.integration.twitter.core.TwitterHeaders;
|
||||
import org.springframework.integration.twitter.core.TwitterOperations;
|
||||
import org.springframework.social.twitter.api.Twitter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -32,12 +32,12 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class DirectMessageSendingMessageHandler extends AbstractMessageHandler {
|
||||
|
||||
private final TwitterOperations twitterOperations;
|
||||
private final Twitter twitter;
|
||||
|
||||
|
||||
public DirectMessageSendingMessageHandler(TwitterOperations twitterOperations) {
|
||||
Assert.notNull(twitterOperations, "twitterOperations must not be null");
|
||||
this.twitterOperations = twitterOperations;
|
||||
public DirectMessageSendingMessageHandler(Twitter twitter) {
|
||||
Assert.notNull(twitter, "twitter must not be null");
|
||||
this.twitter = twitter;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,15 +46,15 @@ public class DirectMessageSendingMessageHandler extends AbstractMessageHandler {
|
||||
Assert.isTrue(message.getPayload() instanceof String, "Only payload of type String is supported. " +
|
||||
"Consider adding a transformer to the message flow in front of this adapter.");
|
||||
Object toUser = message.getHeaders().get(TwitterHeaders.DM_TARGET_USER_ID);
|
||||
Assert.isTrue(toUser instanceof String || toUser instanceof Integer,
|
||||
Assert.isTrue(toUser instanceof String || toUser instanceof Number,
|
||||
"the header '" + TwitterHeaders.DM_TARGET_USER_ID +
|
||||
"' must contain either a String (a screenname) or an int (a user ID)");
|
||||
"' must contain either a String (a screenname) or an number (a user ID)");
|
||||
String payload = (String) message.getPayload();
|
||||
if (toUser instanceof Integer) {
|
||||
this.twitterOperations.sendDirectMessage((Integer) toUser, payload);
|
||||
if (toUser instanceof Number) {
|
||||
this.twitter.directMessageOperations().sendDirectMessage(((Number) toUser).longValue(), payload);
|
||||
}
|
||||
else if (toUser instanceof String) {
|
||||
this.twitterOperations.sendDirectMessage((String) toUser, payload);
|
||||
this.twitter.directMessageOperations().sendDirectMessage((String) toUser, payload);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors
|
||||
* Copyright 2002-2011 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.
|
||||
@@ -19,8 +19,8 @@ package org.springframework.integration.twitter.outbound;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessageHandlingException;
|
||||
import org.springframework.integration.handler.AbstractMessageHandler;
|
||||
import org.springframework.integration.twitter.core.Tweet;
|
||||
import org.springframework.integration.twitter.core.TwitterOperations;
|
||||
import org.springframework.social.twitter.api.Tweet;
|
||||
import org.springframework.social.twitter.api.Twitter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -32,12 +32,12 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class StatusUpdatingMessageHandler extends AbstractMessageHandler {
|
||||
|
||||
private final TwitterOperations twitterOperations;
|
||||
private final Twitter twitter;
|
||||
|
||||
|
||||
public StatusUpdatingMessageHandler(TwitterOperations twitterOperations) {
|
||||
Assert.notNull(twitterOperations, "twitterOperations must not be null");
|
||||
this.twitterOperations = twitterOperations;
|
||||
public StatusUpdatingMessageHandler(Twitter twitter) {
|
||||
Assert.notNull(twitter, "twitter must not be null");
|
||||
this.twitter = twitter;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ public class StatusUpdatingMessageHandler extends AbstractMessageHandler {
|
||||
else {
|
||||
throw new MessageHandlingException(message, "Unsupported payload type '" + payload.getClass().getName() + "'");
|
||||
}
|
||||
this.twitterOperations.updateStatus(statusText);
|
||||
this.twitter.timelineOperations().updateStatus(statusText);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.0.xsd http://www.springframework.org/schema/integration/twitter http://www.springframework.org/schema/integration/twitter/spring-integration-twitter.xsd">
|
||||
|
||||
|
||||
<beans:bean id="twitter" class="org.springframework.integration.twitter.config.TestReceivingMessageSourceParserTests.TwitterTemplateFactoryBean"/>
|
||||
<beans:bean id="twitter" class="org.mockito.Mockito" factory-method="mock">
|
||||
<beans:constructor-arg value="org.springframework.social.twitter.api.Twitter"/>
|
||||
</beans:bean>
|
||||
|
||||
<channel id="inbound_mentions"/>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 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.
|
||||
@@ -16,53 +16,41 @@
|
||||
|
||||
package org.springframework.integration.twitter.config;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.integration.twitter.inbound.DirectMessageReceivingMessageSource;
|
||||
import org.springframework.integration.twitter.inbound.MentionsReceivingMessageSource;
|
||||
import org.springframework.integration.twitter.inbound.TimelineReceivingMessageSource;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.integration.twitter.core.TwitterOperations;
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
*/
|
||||
public class TestReceivingMessageSourceParserTests {
|
||||
|
||||
@org.junit.Test public void test() { }
|
||||
|
||||
|
||||
// NO LONGER RELEVANT...
|
||||
// @Test
|
||||
// public void testRecievingAdapterConfigurationAutoStartup(){
|
||||
// ApplicationContext ac = new ClassPathXmlApplicationContext("TestReceivingMessageSourceParser-context.xml", this.getClass());
|
||||
// SourcePollingChannelAdapter spca = ac.getBean("mentionAdapter", SourcePollingChannelAdapter.class);
|
||||
// SmartLifecycle ms = TestUtils.getPropertyValue(spca, "source", SmartLifecycle.class);
|
||||
// assertFalse(ms.isAutoStartup());
|
||||
//
|
||||
// spca = ac.getBean("dmAdapter", SourcePollingChannelAdapter.class);
|
||||
// ms = TestUtils.getPropertyValue(spca, "source", SmartLifecycle.class);
|
||||
// assertFalse(ms.isAutoStartup());
|
||||
//
|
||||
// spca = ac.getBean("updateAdapter", SourcePollingChannelAdapter.class);
|
||||
// ms = TestUtils.getPropertyValue(spca, "source", SmartLifecycle.class);
|
||||
// assertFalse(ms.isAutoStartup());
|
||||
// }
|
||||
|
||||
@Test
|
||||
public void testReceivingAdapterConfigurationAutoStartup(){
|
||||
ApplicationContext ac = new ClassPathXmlApplicationContext("TestReceivingMessageSourceParser-context.xml", this.getClass());
|
||||
SourcePollingChannelAdapter spca = ac.getBean("mentionAdapter", SourcePollingChannelAdapter.class);
|
||||
MentionsReceivingMessageSource ms = TestUtils.getPropertyValue(spca, "source", MentionsReceivingMessageSource.class);
|
||||
assertNotNull(ms);
|
||||
|
||||
public static class TwitterTemplateFactoryBean implements FactoryBean<TwitterOperations>{
|
||||
spca = ac.getBean("dmAdapter", SourcePollingChannelAdapter.class);
|
||||
DirectMessageReceivingMessageSource dms = TestUtils.getPropertyValue(spca, "source", DirectMessageReceivingMessageSource.class);
|
||||
assertNotNull(dms);
|
||||
|
||||
public TwitterOperations getObject() throws Exception {
|
||||
TwitterOperations oper = mock(TwitterOperations.class);
|
||||
when(oper.getProfileId()).thenReturn("kermit");
|
||||
return oper;
|
||||
}
|
||||
|
||||
public Class<?> getObjectType() {
|
||||
return TwitterOperations.class;
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
spca = ac.getBean("updateAdapter", SourcePollingChannelAdapter.class);
|
||||
|
||||
spca = ac.getBean("updateAdapter", SourcePollingChannelAdapter.class);
|
||||
TimelineReceivingMessageSource tms = TestUtils.getPropertyValue(spca, "source", TimelineReceivingMessageSource.class);
|
||||
assertNotNull(tms);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 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.
|
||||
@@ -16,18 +16,17 @@
|
||||
|
||||
package org.springframework.integration.twitter.config;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertFalse;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.integration.twitter.core.Twitter4jTemplate;
|
||||
import org.springframework.integration.twitter.core.TwitterOperations;
|
||||
import org.springframework.integration.twitter.inbound.SearchReceivingMessageSource;
|
||||
import org.springframework.social.twitter.api.Twitter;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
@@ -35,23 +34,12 @@ import org.springframework.integration.twitter.inbound.SearchReceivingMessageSou
|
||||
public class TestSearchReceivingMessageSourceParserTests {
|
||||
|
||||
@Test
|
||||
@Ignore // because userOpoeration.getProfile() throws exception where it doesn't have to since its a search
|
||||
public void testSearchReceivingDefaultTemplate(){
|
||||
ApplicationContext ac = new ClassPathXmlApplicationContext("TestSearchReceivingMessageSourceParser-context.xml", this.getClass());
|
||||
SourcePollingChannelAdapter spca = ac.getBean("searchAdapter", SourcePollingChannelAdapter.class);
|
||||
SearchReceivingMessageSource ms = (SearchReceivingMessageSource) TestUtils.getPropertyValue(spca, "source");
|
||||
//assertFalse(ms.isAutoStartup());
|
||||
Twitter4jTemplate template = (Twitter4jTemplate) TestUtils.getPropertyValue(ms, "twitterOperations");
|
||||
assertFalse(template.getUnderlyingTwitter().isOAuthEnabled()); // verify anonymous Twitter
|
||||
Twitter template = (Twitter) TestUtils.getPropertyValue(ms, "twitter");
|
||||
assertNotNull(template);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchReceivingCustomTemplate(){
|
||||
ApplicationContext ac = new ClassPathXmlApplicationContext("TestSearchReceivingMessageSourceParser-context.xml", this.getClass());
|
||||
SourcePollingChannelAdapter spca = ac.getBean("searchAdapterWithTemplate", SourcePollingChannelAdapter.class);
|
||||
SearchReceivingMessageSource ms = (SearchReceivingMessageSource) TestUtils.getPropertyValue(spca, "source");
|
||||
//assertFalse(ms.isAutoStartup());
|
||||
TwitterOperations template = (TwitterOperations) TestUtils.getPropertyValue(ms, "twitterOperations");
|
||||
assertEquals(ac.getBean("twitter"), template);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
http://www.springframework.org/schema/integration/twitter http://www.springframework.org/schema/integration/twitter/spring-integration-twitter-2.0.xsd">
|
||||
|
||||
|
||||
<beans:bean id="twitter" class="org.springframework.integration.twitter.core.Twitter4jTemplate"/>
|
||||
<beans:bean id="twitter" class="org.springframework.social.twitter.api.impl.TwitterTemplate"/>
|
||||
|
||||
<channel id="inbound_mentions"/>
|
||||
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
/*
|
||||
* 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.twitter.core;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertNotNull;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
|
||||
import twitter4j.Paging;
|
||||
import twitter4j.Query;
|
||||
import twitter4j.QueryResult;
|
||||
import twitter4j.StatusUpdate;
|
||||
import twitter4j.Twitter;
|
||||
import twitter4j.http.AccessToken;
|
||||
import twitter4j.http.Authorization;
|
||||
import twitter4j.http.OAuthAuthorization;
|
||||
|
||||
/**
|
||||
* Validates that all calls are delegated properly top Twitter
|
||||
*
|
||||
* @author Oleg Zhurakousky
|
||||
*
|
||||
*/
|
||||
public class Twitter4jTemplateTests {
|
||||
Twitter4jTemplate template;
|
||||
Twitter twitter;
|
||||
|
||||
@Before
|
||||
public void prepare() throws Exception{
|
||||
template = new Twitter4jTemplate();
|
||||
Field twitterField = Twitter4jTemplate.class.getDeclaredField("twitter");
|
||||
twitterField.setAccessible(true);
|
||||
twitter = mock(Twitter.class);
|
||||
twitterField.set(template, twitter);
|
||||
}
|
||||
@Test
|
||||
public void testOauthConstructor() throws Exception{
|
||||
template = new Twitter4jTemplate("a", "b", "1234-c", "d");
|
||||
Twitter twitter = (Twitter) TestUtils.getPropertyValue(template, "twitter");
|
||||
Authorization auth = twitter.getAuthorization();
|
||||
assertTrue(twitter.getAuthorization() instanceof OAuthAuthorization);
|
||||
AccessToken accessToken = ((OAuthAuthorization)auth).getOAuthAccessToken();
|
||||
assertEquals("1234-c", accessToken.getToken());
|
||||
assertEquals("d", accessToken.getTokenSecret());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProfileId() throws Exception{
|
||||
when(twitter.getScreenName()).thenReturn("kermit");
|
||||
when(twitter.isOAuthEnabled()).thenReturn(true);
|
||||
assertEquals("kermit", template.getProfileId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDirectMessages() throws Exception{
|
||||
template.getDirectMessages();
|
||||
template.getDirectMessages(123);
|
||||
verify(twitter, times(1)).getDirectMessages();
|
||||
verify(twitter, times(1)).getDirectMessages(Mockito.any(Paging.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMentions() throws Exception{
|
||||
template.getMentions();
|
||||
template.getMentions(123);
|
||||
verify(twitter, times(1)).getMentions();
|
||||
verify(twitter, times(1)).getMentions(Mockito.any(Paging.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetFriendsTimeline() throws Exception{
|
||||
template.getTimeline();
|
||||
template.getTimeline(123);
|
||||
verify(twitter, times(1)).getHomeTimeline();
|
||||
verify(twitter, times(1)).getHomeTimeline(Mockito.any(Paging.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendDirectMessage() throws Exception{
|
||||
template.sendDirectMessage("kermit", "hello");
|
||||
template.sendDirectMessage(1, "hello");
|
||||
verify(twitter, times(1)).sendDirectMessage("kermit", "hello");
|
||||
verify(twitter, times(1)).sendDirectMessage(1, "hello");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateStatus() throws Exception{
|
||||
template.updateStatus("writing twitter test");
|
||||
verify(twitter, times(1)).updateStatus(Mockito.any(StatusUpdate.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearch() throws Exception{
|
||||
// set up test
|
||||
QueryResult result = mock(QueryResult.class);
|
||||
List<twitter4j.Tweet> t4jTweets = new ArrayList<twitter4j.Tweet>();
|
||||
t4jTweets.add(mock(twitter4j.Tweet.class));
|
||||
t4jTweets.add(mock(twitter4j.Tweet.class));
|
||||
t4jTweets.add(mock(twitter4j.Tweet.class));
|
||||
|
||||
when(result.getTweets()).thenReturn(t4jTweets);
|
||||
|
||||
when(twitter.search(Mockito.any(Query.class))).thenReturn(result);
|
||||
// end setup test
|
||||
|
||||
SearchResults results = template.search("#s2gx");
|
||||
List<Tweet> tweets = results.getTweets();
|
||||
assertNotNull(tweets);
|
||||
assertEquals(3, tweets.size());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* 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.twitter.core;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertFalse;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
import static junit.framework.Assert.fail;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import twitter4j.TwitterException;
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
*
|
||||
*/
|
||||
public class TwitterOperationExceptionTests {
|
||||
|
||||
@Test
|
||||
public void test401(){
|
||||
// will result in exception since a,b,c,d are invalid credentials
|
||||
Twitter4jTemplate template = new Twitter4jTemplate("a", "b", "1234-c", "d");
|
||||
try {
|
||||
template.getProfileId();
|
||||
fail();
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof TwitterOperationException);
|
||||
assertEquals(401, ((TwitterOperationException)e).getTwitterStatusCode());
|
||||
}
|
||||
}
|
||||
@Test
|
||||
public void testWithNull(){
|
||||
try {
|
||||
throw new TwitterOperationException();
|
||||
} catch (Exception e) {
|
||||
TwitterOperationException tex = (TwitterOperationException) e;
|
||||
assertFalse(StringUtils.hasText(tex.getMessage()));
|
||||
assertEquals(-1, tex.getTwitterStatusCode());
|
||||
}
|
||||
}
|
||||
@Test
|
||||
public void testWithTwitterException(){
|
||||
try {
|
||||
throw new TwitterOperationException(new TwitterException("foo"));
|
||||
} catch (Exception e) {
|
||||
TwitterOperationException tex = (TwitterOperationException) e;
|
||||
assertTrue(StringUtils.hasText(tex.getMessage()));
|
||||
assertTrue(tex.getMessage().contains("foo"));
|
||||
assertEquals(-1, tex.getTwitterStatusCode());
|
||||
}
|
||||
}
|
||||
@Test
|
||||
public void testWithDescription(){
|
||||
try {
|
||||
throw new TwitterOperationException("foo");
|
||||
} catch (Exception e) {
|
||||
TwitterOperationException tex = (TwitterOperationException) e;
|
||||
assertTrue(StringUtils.hasText(tex.getMessage()));
|
||||
assertTrue(tex.getMessage().contains("foo"));
|
||||
assertEquals(-1, tex.getTwitterStatusCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,41 +18,40 @@
|
||||
|
||||
<message-history/>
|
||||
|
||||
<context:property-placeholder
|
||||
location="classpath:twitter.receiver.properties"
|
||||
ignore-unresolvable="true"/>
|
||||
|
||||
<context:property-placeholder location="classpath:sample.properties"/>
|
||||
|
||||
<channel id="inbound_dm"/>
|
||||
<channel id="inbound_mentions"/>
|
||||
<channel id="inbound_updates"/>
|
||||
<channel id="inbound_search"/>
|
||||
|
||||
<beans:bean id="twitterTemplate" class="org.springframework.integration.twitter.core.Twitter4jTemplate">
|
||||
<beans:constructor-arg value="${twitter.oauth.consumerKey}"/>
|
||||
<beans:constructor-arg value="${twitter.oauth.consumerSecret}"/>
|
||||
<beans:constructor-arg value="${twitter.oauth.accessToken}"/>
|
||||
<beans:constructor-arg value="${twitter.oauth.accessTokenSecret}"/>
|
||||
<beans:bean id="twitterTemplate" class="org.springframework.social.twitter.api.impl.TwitterTemplate">
|
||||
<beans:constructor-arg value="${z_oleg.oauth.consumerKey}"/>
|
||||
<beans:constructor-arg value="${z_oleg.oauth.consumerSecret}"/>
|
||||
<beans:constructor-arg value="${z_oleg.oauth.accessToken}"/>
|
||||
<beans:constructor-arg value="${z_oleg.oauth.accessTokenSecret}"/>
|
||||
</beans:bean>
|
||||
|
||||
<twitter:mentions-inbound-channel-adapter twitter-template="twitterTemplate" channel="inbound_mentions">
|
||||
<poller fixed-rate="5000" max-messages-per-poll="3"/>
|
||||
</twitter:mentions-inbound-channel-adapter>
|
||||
<service-activator input-channel="inbound_mentions" ref="twitterAnnouncer" method="mention"/>
|
||||
|
||||
<!-- <twitter:dm-inbound-channel-adapter twitter-template="twitterTemplate" channel="inbound_dm">-->
|
||||
<!-- <poller fixed-rate="5000" max-messages-per-poll="3"/>-->
|
||||
<!-- </twitter:dm-inbound-channel-adapter>-->
|
||||
<!-- <service-activator input-channel="inbound_dm" ref="twitterAnnouncer" method="dm"/>-->
|
||||
<!-- <twitter:mentions-inbound-channel-adapter twitter-template="twitterTemplate" channel="inbound_mentions"> -->
|
||||
<!-- <poller fixed-rate="5000" max-messages-per-poll="-1"/> -->
|
||||
<!-- </twitter:mentions-inbound-channel-adapter> -->
|
||||
|
||||
<!-- <twitter:search-inbound-channel-adapter id="searchAdapter" channel="inbound_search" query="#springintegration">-->
|
||||
<!-- <poller fixed-rate="5000" max-messages-per-poll="5"/>-->
|
||||
<!-- </twitter:search-inbound-channel-adapter>-->
|
||||
<!-- <service-activator input-channel="inbound_search" ref="twitterAnnouncer" method="search"/>-->
|
||||
<!-- <service-activator input-channel="inbound_mentions" ref="twitterAnnouncer" method="mention"/> -->
|
||||
|
||||
<!-- <twitter:inbound-channel-adapter id="twitterInbound" twitter-template="twitterTemplate" channel="inbound_updates">-->
|
||||
<!-- <poller fixed-rate="1000" max-messages-per-poll="3"/>-->
|
||||
<!-- </twitter:inbound-channel-adapter>-->
|
||||
<!-- <service-activator input-channel="inbound_updates" ref="twitterAnnouncer" method="updates"/>-->
|
||||
<!-- <twitter:dm-inbound-channel-adapter twitter-template="twitterTemplate" channel="inbound_dm"> -->
|
||||
<!-- <poller fixed-rate="5000" max-messages-per-poll="-1"/> -->
|
||||
<!-- </twitter:dm-inbound-channel-adapter> -->
|
||||
<!-- <service-activator input-channel="inbound_dm" ref="twitterAnnouncer" method="dm"/> -->
|
||||
|
||||
<!-- <twitter:search-inbound-channel-adapter id="searchAdapter" twitter-template="twitterTemplate" channel="inbound_search" query="#springintegration"> -->
|
||||
<!-- <poller fixed-rate="5000" max-messages-per-poll="5"/> -->
|
||||
<!-- </twitter:search-inbound-channel-adapter> -->
|
||||
<!-- <service-activator input-channel="inbound_search" ref="twitterAnnouncer" method="search"/> -->
|
||||
|
||||
<twitter:inbound-channel-adapter id="twitterInbound" twitter-template="twitterTemplate" channel="inbound_updates">
|
||||
<poller fixed-rate="1000" max-messages-per-poll="3"/>
|
||||
</twitter:inbound-channel-adapter>
|
||||
<service-activator input-channel="inbound_updates" ref="twitterAnnouncer" method="updates"/>
|
||||
|
||||
<beans:bean id="twitterAnnouncer" class="org.springframework.integration.twitter.ignored.TwitterAnnouncer"/>
|
||||
</beans:beans>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
location="classpath:twitter.sender.properties"
|
||||
ignore-unresolvable="true"/>
|
||||
|
||||
<beans:bean id="twitterTemplate" class="org.springframework.integration.twitter.core.Twitter4jTemplate">
|
||||
<beans:bean id="twitterTemplate" class="org.springframework.social.twitter.api.impl.TwitterTemplate">
|
||||
<beans:constructor-arg value="${twitter.oauth.consumerKey}"/>
|
||||
<beans:constructor-arg value="${twitter.oauth.consumerSecret}"/>
|
||||
<beans:constructor-arg value="${twitter.oauth.accessToken}"/>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
location="classpath:twitter.receiver.properties"
|
||||
ignore-unresolvable="true"/>
|
||||
|
||||
<beans:bean id="twitterTemplate" class="org.springframework.integration.twitter.core.Twitter4jTemplate">
|
||||
<beans:bean id="twitterTemplate" class="org.springframework.social.twitter.api.impl.TwitterTemplate">
|
||||
<beans:constructor-arg value="${twitter.oauth.consumerKey}"/>
|
||||
<beans:constructor-arg value="${twitter.oauth.consumerSecret}"/>
|
||||
<beans:constructor-arg value="${twitter.oauth.accessToken}"/>
|
||||
|
||||
@@ -18,15 +18,16 @@ package org.springframework.integration.twitter.ignored;
|
||||
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.history.MessageHistory;
|
||||
import org.springframework.integration.twitter.core.Tweet;
|
||||
import org.springframework.social.twitter.api.DirectMessage;
|
||||
import org.springframework.social.twitter.api.Tweet;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class TwitterAnnouncer {
|
||||
|
||||
public void dm(Tweet directMessage) {
|
||||
public void dm(DirectMessage directMessage) {
|
||||
System.out.println("A direct message has been received from " +
|
||||
directMessage.getFromUser() + " with text " + directMessage.getText());
|
||||
directMessage.getSender().getScreenName() + " with text " + directMessage.getText());
|
||||
}
|
||||
|
||||
public void search(Message<?> search) {
|
||||
|
||||
@@ -16,197 +16,42 @@
|
||||
|
||||
package org.springframework.integration.twitter.inbound;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertNotNull;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import java.util.Properties;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.PropertiesFactoryBean;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.context.IntegrationContextUtils;
|
||||
import org.springframework.integration.store.PropertiesPersistingMetadataStore;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.integration.twitter.core.Tweet;
|
||||
import org.springframework.integration.twitter.core.Twitter4jTemplate;
|
||||
import org.springframework.integration.twitter.core.TwitterOperations;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
|
||||
import twitter4j.DirectMessage;
|
||||
import twitter4j.Paging;
|
||||
import twitter4j.RateLimitStatus;
|
||||
import twitter4j.ResponseList;
|
||||
import twitter4j.Twitter;
|
||||
import org.springframework.social.twitter.api.DirectMessage;
|
||||
import org.springframework.social.twitter.api.impl.TwitterTemplate;
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
*/
|
||||
public class DirectMessageReceivingMessageSourceTests {
|
||||
|
||||
private DirectMessage firstMessage;
|
||||
|
||||
private DirectMessage secondMessage;
|
||||
|
||||
private DirectMessage thirdMessage;
|
||||
|
||||
private DirectMessage fourthMessage;
|
||||
|
||||
private TwitterOperations twitter;
|
||||
|
||||
Twitter tw;
|
||||
|
||||
|
||||
@Before
|
||||
public void prepare() throws Exception{
|
||||
twitter = new Twitter4jTemplate();
|
||||
|
||||
firstMessage = mock(DirectMessage.class);
|
||||
when(firstMessage.getCreatedAt()).thenReturn(new Date(5555555555L));
|
||||
when(firstMessage.getId()).thenReturn( (long) 200);
|
||||
|
||||
secondMessage = mock(DirectMessage.class);
|
||||
when(secondMessage.getCreatedAt()).thenReturn(new Date(2222222222L));
|
||||
when(secondMessage.getId()).thenReturn( (long) 2000);
|
||||
|
||||
thirdMessage = mock(DirectMessage.class);
|
||||
when(thirdMessage.getCreatedAt()).thenReturn(new Date(66666666666L));
|
||||
when(thirdMessage.getId()).thenReturn( (long) 3000);
|
||||
|
||||
fourthMessage = mock(DirectMessage.class);
|
||||
when(fourthMessage.getCreatedAt()).thenReturn(new Date(77777777777L));
|
||||
when(fourthMessage.getId()).thenReturn( (long) 4000);
|
||||
|
||||
tw = mock(Twitter.class);
|
||||
Field twField = Twitter4jTemplate.class.getDeclaredField("twitter");
|
||||
twField.setAccessible(true);
|
||||
twField.set(twitter, tw);
|
||||
when(tw.getScreenName()).thenReturn("kermit");
|
||||
|
||||
twitter = spy(twitter);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSuccessfullInitialization() throws Exception{
|
||||
when(tw.isOAuthEnabled()).thenReturn(true);
|
||||
DirectMessageReceivingMessageSource source = new DirectMessageReceivingMessageSource(twitter);
|
||||
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
|
||||
scheduler.afterPropertiesSet();
|
||||
source.setBeanName("twitterEndpoint");
|
||||
source.afterPropertiesSet();
|
||||
assertEquals("twitter:dm-inbound-channel-adapter.twitterEndpoint.kermit", TestUtils.getPropertyValue(source, "metadataKey"));
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
@Test
|
||||
public void testSuccessfullInitializationWithMessages() throws Exception{
|
||||
this.setUpMockScenarioForMessagePolling();
|
||||
|
||||
DirectMessageReceivingMessageSource source = new DirectMessageReceivingMessageSource(twitter);
|
||||
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
|
||||
scheduler.afterPropertiesSet();
|
||||
source.setBeanName("twitterEndpoint");
|
||||
source.afterPropertiesSet();
|
||||
Message<Tweet> msg = (Message<Tweet>) source.receive();
|
||||
assertNotNull(msg);
|
||||
|
||||
Tweet message = msg.getPayload();
|
||||
assertEquals(2000, message.getId());
|
||||
Thread.sleep(1000);
|
||||
verify(twitter, times(1)).getDirectMessages();
|
||||
}
|
||||
/**
|
||||
* This test will validate that last status is initialized from the metadatastore
|
||||
* @throws Exception
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void testSuccessfullInitializationWithMessagesWithPersistentMetadata() throws Exception{
|
||||
String fileName = System.getProperty("java.io.tmpdir") + "/spring-integration/metadata-store.properties";
|
||||
File file = new File(fileName);
|
||||
if (file.exists()){
|
||||
file.delete();
|
||||
}
|
||||
this.setUpMockScenarioForMessagePolling();
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
PropertiesPersistingMetadataStore store = new PropertiesPersistingMetadataStore();
|
||||
store.afterPropertiesSet();
|
||||
bf.registerSingleton(IntegrationContextUtils.METADATA_STORE_BEAN_NAME, store);
|
||||
DirectMessageReceivingMessageSource source = new DirectMessageReceivingMessageSource(twitter);
|
||||
source.setBeanFactory(bf);
|
||||
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
|
||||
scheduler.afterPropertiesSet();
|
||||
source.setBeanName("twitterEndpoint");
|
||||
source.afterPropertiesSet();
|
||||
Message msg = source.receive();
|
||||
assertNotNull(msg);
|
||||
Tweet tweet = (Tweet) msg.getPayload();
|
||||
|
||||
|
||||
// Resuming
|
||||
this.prepare();
|
||||
this.setUpMockScenarioForMessagePolling();
|
||||
store.destroy();
|
||||
bf = new DefaultListableBeanFactory();
|
||||
store = new PropertiesPersistingMetadataStore();
|
||||
store.afterPropertiesSet();
|
||||
bf.registerSingleton(IntegrationContextUtils.METADATA_STORE_BEAN_NAME, store);
|
||||
source = new DirectMessageReceivingMessageSource(twitter);
|
||||
source.setBeanFactory(bf);
|
||||
scheduler = new ThreadPoolTaskScheduler();
|
||||
scheduler.afterPropertiesSet();
|
||||
source.setBeanName("twitterEndpoint");
|
||||
source.afterPropertiesSet();
|
||||
msg = source.receive();
|
||||
tweet = (Tweet) msg.getPayload();
|
||||
assertEquals(3000, tweet.getId());
|
||||
msg = source.receive();
|
||||
tweet = (Tweet) msg.getPayload();
|
||||
assertEquals(4000, tweet.getId());
|
||||
file.delete();
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void setUpMockScenarioForMessagePolling() throws Exception{
|
||||
RateLimitStatus rateLimitStatus = mock(RateLimitStatus.class);
|
||||
when(tw.isOAuthEnabled()).thenReturn(true);
|
||||
when(tw.getRateLimitStatus()).thenReturn(rateLimitStatus);
|
||||
when(rateLimitStatus.getSecondsUntilReset()).thenReturn(1000);
|
||||
when(rateLimitStatus.getRemainingHits()).thenReturn(1000);
|
||||
|
||||
SampleResoponceList testMessages = new SampleResoponceList();
|
||||
testMessages.add(firstMessage);
|
||||
testMessages.add(secondMessage);
|
||||
when(tw.getDirectMessages()).thenReturn(testMessages);
|
||||
|
||||
testMessages = new SampleResoponceList();
|
||||
testMessages.add(thirdMessage);
|
||||
testMessages.add(fourthMessage);
|
||||
when(tw.getDirectMessages(Mockito.any(Paging.class))).thenReturn(testMessages);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "serial" })
|
||||
public static class SampleResoponceList extends ArrayList implements ResponseList {
|
||||
|
||||
public RateLimitStatus getRateLimitStatus() {
|
||||
return mock(RateLimitStatus.class);
|
||||
@Test @Ignore
|
||||
public void demoReceiveDm() throws Exception{
|
||||
PropertiesFactoryBean pf = new PropertiesFactoryBean();
|
||||
pf.setLocation(new ClassPathResource("sample.properties"));
|
||||
pf.afterPropertiesSet();
|
||||
Properties prop = pf.getObject();
|
||||
System.out.println(prop);
|
||||
TwitterTemplate template = new TwitterTemplate(prop.getProperty("z_oleg.oauth.consumerKey"),
|
||||
prop.getProperty("z_oleg.oauth.consumerSecret"),
|
||||
prop.getProperty("z_oleg.oauth.accessToken"),
|
||||
prop.getProperty("z_oleg.oauth.accessTokenSecret"));
|
||||
DirectMessageReceivingMessageSource tSource = new DirectMessageReceivingMessageSource(template);
|
||||
tSource.afterPropertiesSet();
|
||||
for (int i = 0; i < 50; i++) {
|
||||
Message<DirectMessage> message = (Message<DirectMessage>) tSource.receive();
|
||||
if (message != null){
|
||||
DirectMessage tweet = message.getPayload();
|
||||
System.out.println(tweet.getSender().getScreenName() + " - " + tweet.getText() + " - " + tweet.getCreatedAt());
|
||||
}
|
||||
}
|
||||
|
||||
public RateLimitStatus getFeatureSpecificRateLimitStatus() {
|
||||
return mock(RateLimitStatus.class);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,17 +16,15 @@
|
||||
|
||||
package org.springframework.integration.twitter.inbound;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.PropertiesFactoryBean;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessagingException;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.integration.core.MessageHandler;
|
||||
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
|
||||
import org.springframework.integration.twitter.core.Tweet;
|
||||
import org.springframework.integration.twitter.core.Twitter4jTemplate;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
import org.springframework.social.twitter.api.Tweet;
|
||||
import org.springframework.social.twitter.api.impl.TwitterTemplate;
|
||||
|
||||
|
||||
/**
|
||||
@@ -34,37 +32,28 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
*/
|
||||
public class SearchReceivingMessageSourceTests {
|
||||
|
||||
/**
|
||||
* THis test is a sample test and wil require connecting to a real Twitter
|
||||
* however no OAuth is required sincxe uts a search, so simply uncomment and run
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testSearchReceiving() throws Exception{
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
|
||||
scheduler.afterPropertiesSet();
|
||||
bf.registerSingleton("taskScheduler", scheduler);
|
||||
SearchReceivingMessageSource ms = new SearchReceivingMessageSource(new Twitter4jTemplate());
|
||||
DirectChannel channel = new DirectChannel();
|
||||
channel.subscribe(new MessageHandler() {
|
||||
public void handleMessage(Message<?> message) throws MessagingException {
|
||||
System.out.println("Message: " + ((Tweet)message.getPayload()).getCreatedAt() + " - " + ((Tweet)message.getPayload()).getText());
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test @Ignore
|
||||
public void demoReceiveSearchResults() throws Exception{
|
||||
PropertiesFactoryBean pf = new PropertiesFactoryBean();
|
||||
pf.setLocation(new ClassPathResource("sample.properties"));
|
||||
pf.afterPropertiesSet();
|
||||
Properties prop = pf.getObject();
|
||||
System.out.println(prop);
|
||||
TwitterTemplate template = new TwitterTemplate(prop.getProperty("z_oleg.oauth.consumerKey"),
|
||||
prop.getProperty("z_oleg.oauth.consumerSecret"),
|
||||
prop.getProperty("z_oleg.oauth.accessToken"),
|
||||
prop.getProperty("z_oleg.oauth.accessTokenSecret"));
|
||||
SearchReceivingMessageSource tSource = new SearchReceivingMessageSource(template);
|
||||
tSource.setQuery("#springsocial");
|
||||
tSource.afterPropertiesSet();
|
||||
for (int i = 0; i < 50; i++) {
|
||||
Message<Tweet> message = (Message<Tweet>) tSource.receive();
|
||||
if (message != null){
|
||||
Tweet tweet = message.getPayload();
|
||||
System.out.println(tweet.getFromUser() + " - " + tweet.getText() + " - " + tweet.getCreatedAt());
|
||||
}
|
||||
});
|
||||
SourcePollingChannelAdapter adapter = new SourcePollingChannelAdapter();
|
||||
adapter.setSource(ms);
|
||||
adapter.setBeanFactory(bf);
|
||||
adapter.setOutputChannel(channel);
|
||||
adapter.afterPropertiesSet();
|
||||
adapter.start();
|
||||
ms.setBeanFactory(bf);
|
||||
ms.setQuery("#springintegration");
|
||||
//ms.setTaskScheduler(scheduler);
|
||||
ms.afterPropertiesSet();
|
||||
//ms.start();
|
||||
System.in.read();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,197 +16,43 @@
|
||||
|
||||
package org.springframework.integration.twitter.inbound;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertNotNull;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import java.util.Properties;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.PropertiesFactoryBean;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.context.IntegrationContextUtils;
|
||||
import org.springframework.integration.store.PropertiesPersistingMetadataStore;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.integration.twitter.core.Tweet;
|
||||
import org.springframework.integration.twitter.core.Twitter4jTemplate;
|
||||
import org.springframework.integration.twitter.core.TwitterOperations;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
import org.springframework.social.twitter.api.Tweet;
|
||||
import org.springframework.social.twitter.api.impl.TwitterTemplate;
|
||||
|
||||
import twitter4j.Paging;
|
||||
import twitter4j.RateLimitStatus;
|
||||
import twitter4j.ResponseList;
|
||||
import twitter4j.Status;
|
||||
import twitter4j.Twitter;
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
*/
|
||||
public class TimelineReceivingMessageSourceTests {
|
||||
|
||||
private Status firstMessage;
|
||||
|
||||
private Status secondMessage;
|
||||
|
||||
private Status thirdMessage;
|
||||
|
||||
private Status fourthMessage;
|
||||
|
||||
private TwitterOperations twitter;
|
||||
|
||||
Twitter tw;
|
||||
|
||||
|
||||
@Before
|
||||
public void prepare() throws Exception{
|
||||
twitter = new Twitter4jTemplate();
|
||||
|
||||
firstMessage = mock(Status.class);
|
||||
when(firstMessage.getCreatedAt()).thenReturn(new Date(5555555555L));
|
||||
when(firstMessage.getId()).thenReturn( (long) 200);
|
||||
|
||||
secondMessage = mock(Status.class);
|
||||
when(secondMessage.getCreatedAt()).thenReturn(new Date(2222222222L));
|
||||
when(secondMessage.getId()).thenReturn((long) 2000);
|
||||
|
||||
thirdMessage = mock(Status.class);
|
||||
when(thirdMessage.getCreatedAt()).thenReturn(new Date(66666666666L));
|
||||
when(thirdMessage.getId()).thenReturn((long) 3000);
|
||||
|
||||
fourthMessage = mock(Status.class);
|
||||
when(fourthMessage.getCreatedAt()).thenReturn(new Date(77777777777L));
|
||||
when(fourthMessage.getId()).thenReturn( (long)4000);
|
||||
|
||||
tw = mock(Twitter.class);
|
||||
Field twField = Twitter4jTemplate.class.getDeclaredField("twitter");
|
||||
twField.setAccessible(true);
|
||||
twField.set(twitter, tw);
|
||||
when(tw.getScreenName()).thenReturn("kermit");
|
||||
|
||||
twitter = spy(twitter);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSuccessfulInitialization() throws Exception{
|
||||
when(tw.isOAuthEnabled()).thenReturn(true);
|
||||
TimelineReceivingMessageSource source = new TimelineReceivingMessageSource(twitter);
|
||||
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
|
||||
scheduler.afterPropertiesSet();
|
||||
source.setBeanName("twitterEndpoint");
|
||||
source.afterPropertiesSet();
|
||||
assertEquals("twitter:inbound-channel-adapter.twitterEndpoint.kermit", TestUtils.getPropertyValue(source, "metadataKey"));
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void testSuccessfulInitializationWithMessages() throws Exception{
|
||||
this.setUpMockScenarioForMessagePolling();
|
||||
|
||||
TimelineReceivingMessageSource source = new TimelineReceivingMessageSource(twitter);
|
||||
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
|
||||
scheduler.afterPropertiesSet();
|
||||
source.setBeanName("twitterEndpoint");
|
||||
source.afterPropertiesSet();
|
||||
Message msg = source.receive();
|
||||
assertNotNull(msg);
|
||||
Tweet message = (Tweet) msg.getPayload();
|
||||
assertEquals(2000, message.getId());
|
||||
verify(twitter, times(1)).getTimeline();
|
||||
}
|
||||
/**
|
||||
* This test will validate that last status is initilaized from the metadatastore
|
||||
* @throws Exception
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void testSuccessfulInitializationWithMessagesWithPersistentMetadata() throws Exception{
|
||||
String fileName = System.getProperty("java.io.tmpdir") + "/spring-integration/metadata-store.properties";
|
||||
File file = new File(fileName);
|
||||
if (file.exists()){
|
||||
file.delete();
|
||||
}
|
||||
this.setUpMockScenarioForMessagePolling();
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
PropertiesPersistingMetadataStore store = new PropertiesPersistingMetadataStore();
|
||||
store.afterPropertiesSet();
|
||||
bf.registerSingleton(IntegrationContextUtils.METADATA_STORE_BEAN_NAME, store);
|
||||
TimelineReceivingMessageSource source = new TimelineReceivingMessageSource(twitter);
|
||||
source.setBeanFactory(bf);
|
||||
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
|
||||
scheduler.afterPropertiesSet();
|
||||
source.setBeanName("twitterEndpoint");
|
||||
source.afterPropertiesSet();
|
||||
|
||||
Message message = source.receive();
|
||||
Tweet tweet = (Tweet) message.getPayload();
|
||||
assertEquals(2000, tweet.getId());
|
||||
|
||||
|
||||
// Resuming
|
||||
this.prepare();
|
||||
this.setUpMockScenarioForMessagePolling();
|
||||
store.destroy();
|
||||
bf = new DefaultListableBeanFactory();
|
||||
store = new PropertiesPersistingMetadataStore();
|
||||
store.afterPropertiesSet();
|
||||
bf.registerSingleton(IntegrationContextUtils.METADATA_STORE_BEAN_NAME, store);
|
||||
source = new TimelineReceivingMessageSource(twitter);
|
||||
source.setBeanFactory(bf);
|
||||
scheduler = new ThreadPoolTaskScheduler();
|
||||
scheduler.afterPropertiesSet();
|
||||
source.setBeanName("twitterEndpoint");
|
||||
source.afterPropertiesSet();
|
||||
|
||||
message = source.receive();
|
||||
tweet = (Tweet) message.getPayload();
|
||||
assertEquals(3000, tweet.getId());
|
||||
message = source.receive();
|
||||
tweet = (Tweet) message.getPayload();
|
||||
assertEquals(4000, tweet.getId());
|
||||
file.delete();
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void setUpMockScenarioForMessagePolling() throws Exception{
|
||||
RateLimitStatus rateLimitStatus = mock(RateLimitStatus.class);
|
||||
|
||||
when(tw.getRateLimitStatus()).thenReturn(rateLimitStatus);
|
||||
when(rateLimitStatus.getSecondsUntilReset()).thenReturn(1000);
|
||||
when(rateLimitStatus.getRemainingHits()).thenReturn(1000);
|
||||
|
||||
SampleResoponceList testMessages = new SampleResoponceList();
|
||||
testMessages.add(firstMessage);
|
||||
testMessages.add(secondMessage);
|
||||
when(tw.getHomeTimeline()).thenReturn(testMessages);
|
||||
|
||||
testMessages = new SampleResoponceList();
|
||||
testMessages.add(thirdMessage);
|
||||
testMessages.add(fourthMessage);
|
||||
when(tw.getHomeTimeline(Mockito.any(Paging.class))).thenReturn(testMessages);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "serial" })
|
||||
public static class SampleResoponceList extends ArrayList implements ResponseList {
|
||||
|
||||
public RateLimitStatus getRateLimitStatus() {
|
||||
return mock(RateLimitStatus.class);
|
||||
@Test @Ignore
|
||||
public void demoReceiveTimeline() throws Exception{
|
||||
PropertiesFactoryBean pf = new PropertiesFactoryBean();
|
||||
pf.setLocation(new ClassPathResource("sample.properties"));
|
||||
pf.afterPropertiesSet();
|
||||
Properties prop = pf.getObject();
|
||||
System.out.println(prop);
|
||||
TwitterTemplate template = new TwitterTemplate(prop.getProperty("z_oleg.oauth.consumerKey"),
|
||||
prop.getProperty("z_oleg.oauth.consumerSecret"),
|
||||
prop.getProperty("z_oleg.oauth.accessToken"),
|
||||
prop.getProperty("z_oleg.oauth.accessTokenSecret"));
|
||||
TimelineReceivingMessageSource tSource = new TimelineReceivingMessageSource(template);
|
||||
tSource.afterPropertiesSet();
|
||||
for (int i = 0; i < 50; i++) {
|
||||
Message<Tweet> message = (Message<Tweet>) tSource.receive();
|
||||
if (message != null){
|
||||
Tweet tweet = message.getPayload();
|
||||
System.out.println(tweet.getFromUser() + " - " + tweet.getText() + " - " + tweet.getCreatedAt());
|
||||
}
|
||||
}
|
||||
|
||||
public RateLimitStatus getFeatureSpecificRateLimitStatus() {
|
||||
return mock(RateLimitStatus.class);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,16 +16,16 @@
|
||||
|
||||
package org.springframework.integration.twitter.outbound;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.config.PropertiesFactoryBean;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.integration.twitter.core.TwitterHeaders;
|
||||
import org.springframework.integration.twitter.core.TwitterOperations;
|
||||
import org.springframework.social.twitter.api.impl.TwitterTemplate;
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
@@ -33,20 +33,22 @@ import org.springframework.integration.twitter.core.TwitterOperations;
|
||||
*/
|
||||
public class DirectMessageSendingMessageHandlerTests {
|
||||
|
||||
private TwitterOperations twitter = mock(TwitterOperations.class);
|
||||
|
||||
@Test
|
||||
@Test @Ignore
|
||||
public void validateSendDirectMessage() throws Exception{
|
||||
Message<?> message1 = MessageBuilder.withPayload("hello")
|
||||
.setHeader(TwitterHeaders.DM_TARGET_USER_ID, "foo").build();
|
||||
DirectMessageSendingMessageHandler handler = new DirectMessageSendingMessageHandler(twitter);
|
||||
PropertiesFactoryBean pf = new PropertiesFactoryBean();
|
||||
pf.setLocation(new ClassPathResource("sample.properties"));
|
||||
pf.afterPropertiesSet();
|
||||
Properties prop = pf.getObject();
|
||||
System.out.println(prop);
|
||||
TwitterTemplate template = new TwitterTemplate(prop.getProperty("spring_eip.oauth.consumerKey"),
|
||||
prop.getProperty("spring_eip.oauth.consumerSecret"),
|
||||
prop.getProperty("spring_eip.oauth.accessToken"),
|
||||
prop.getProperty("spring_eip.oauth.accessTokenSecret"));
|
||||
Message<?> message1 = MessageBuilder.withPayload("Polsihing SI Twitter migration")
|
||||
.setHeader(TwitterHeaders.DM_TARGET_USER_ID, "z_oleg").build();
|
||||
DirectMessageSendingMessageHandler handler = new DirectMessageSendingMessageHandler(template);
|
||||
handler.afterPropertiesSet();
|
||||
handler.handleMessage(message1);
|
||||
verify(twitter, times(1)).sendDirectMessage("foo", "hello");
|
||||
Message<?> message2 = MessageBuilder.withPayload("hello")
|
||||
.setHeader(TwitterHeaders.DM_TARGET_USER_ID, 123).build();;
|
||||
handler.handleMessage(message2);
|
||||
verify(twitter, times(1)).sendDirectMessage(123, "hello");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,64 +16,37 @@
|
||||
|
||||
package org.springframework.integration.twitter.outbound;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import java.util.Properties;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.beans.factory.config.PropertiesFactoryBean;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.integration.twitter.core.Tweet;
|
||||
import org.springframework.integration.twitter.core.Twitter4jTemplate;
|
||||
import org.springframework.integration.twitter.core.TwitterOperations;
|
||||
|
||||
import twitter4j.StatusUpdate;
|
||||
import twitter4j.Twitter;
|
||||
import org.springframework.social.twitter.api.impl.TwitterTemplate;
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
* @since 2.0
|
||||
*/
|
||||
public class StatusUpdatingMessageHandlerTests {
|
||||
|
||||
|
||||
TwitterOperations twitterOperations;
|
||||
|
||||
Twitter twitter;
|
||||
|
||||
@Before
|
||||
public void prepare() throws Exception{
|
||||
twitterOperations = spy(new Twitter4jTemplate());
|
||||
Field twitterField = Twitter4jTemplate.class.getDeclaredField("twitter");
|
||||
twitterField.setAccessible(true);
|
||||
twitter = mock(Twitter.class);
|
||||
twitterField.set(twitterOperations, twitter);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void testSendingStatusUpdate() throws Exception{
|
||||
StatusUpdatingMessageHandler handler = new StatusUpdatingMessageHandler(twitterOperations);
|
||||
Tweet tweet = new Tweet();
|
||||
tweet.setText("writing twitter tests");
|
||||
handler.handleMessage(new GenericMessage(tweet));
|
||||
verify(twitterOperations, times(1)).updateStatus(Mockito.any(String.class));
|
||||
verify(twitter, times(1)).updateStatus(Mockito.any(StatusUpdate.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendingStatusUpdateWithStringPayload() throws Exception{
|
||||
StatusUpdatingMessageHandler handler = new StatusUpdatingMessageHandler(twitterOperations);
|
||||
Message<?> message = MessageBuilder.withPayload("writing twitter tests").build();
|
||||
handler.handleMessage(message);
|
||||
verify(twitterOperations, times(1)).updateStatus(Mockito.any(String.class));
|
||||
verify(twitter, times(1)).updateStatus(Mockito.any(StatusUpdate.class));
|
||||
@Test @Ignore
|
||||
public void demoSendStatusMessage() throws Exception{
|
||||
PropertiesFactoryBean pf = new PropertiesFactoryBean();
|
||||
pf.setLocation(new ClassPathResource("sample.properties"));
|
||||
pf.afterPropertiesSet();
|
||||
Properties prop = pf.getObject();
|
||||
TwitterTemplate template = new TwitterTemplate(prop.getProperty("z_oleg.oauth.consumerKey"),
|
||||
prop.getProperty("z_oleg.oauth.consumerSecret"),
|
||||
prop.getProperty("z_oleg.oauth.accessToken"),
|
||||
prop.getProperty("z_oleg.oauth.accessTokenSecret"));
|
||||
Message<?> message1 = MessageBuilder.withPayload("Ppolishing #springintegration migration to Spring Social. test").build();
|
||||
StatusUpdatingMessageHandler handler = new StatusUpdatingMessageHandler(template);
|
||||
handler.afterPropertiesSet();
|
||||
handler.handleMessage(message1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user