INT-1603 first round of changes to introduce search methods to TwitterOperation and Twiter4JTemplate as well as allign TwitterOperation with its counterpart in Spring Social. Also copied SearchResult from Spring Social
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
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;
|
||||
private boolean lastPage;
|
||||
|
||||
public SearchResults(List<Tweet> tweets, long maxId, long sinceId, boolean lastPage) {
|
||||
this.tweets = tweets;
|
||||
this.maxId = maxId;
|
||||
this.sinceId = sinceId;
|
||||
this.lastPage = lastPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if this is the last page of matching
|
||||
* {@link Tweet}s; <code>false</code> if there are more pages that follow
|
||||
* this one.
|
||||
*/
|
||||
public boolean isLastPage() {
|
||||
return lastPage;
|
||||
}
|
||||
}
|
||||
@@ -15,13 +15,19 @@
|
||||
*/
|
||||
package org.springframework.integration.twitter.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang.NotImplementedException;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import twitter4j.DirectMessage;
|
||||
import twitter4j.IDs;
|
||||
import twitter4j.Paging;
|
||||
import twitter4j.Query;
|
||||
import twitter4j.QueryResult;
|
||||
import twitter4j.ResponseList;
|
||||
import twitter4j.Status;
|
||||
import twitter4j.StatusUpdate;
|
||||
@@ -159,13 +165,10 @@ public class Twitter4jTemplate implements TwitterOperations{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStatus(Tweet statusTweet) {
|
||||
Assert.notNull(statusTweet, "'statusTweet' must not be null");
|
||||
public void updateStatus(String statusTweet) {
|
||||
Assert.hasText(statusTweet, "'statusTweet' must not be null");
|
||||
try {
|
||||
StatusUpdate status = new StatusUpdate(statusTweet.getText());
|
||||
if (statusTweet.getToUserId() != null){
|
||||
status.setInReplyToStatusId(statusTweet.getToUserId());
|
||||
}
|
||||
StatusUpdate status = new StatusUpdate(statusTweet);
|
||||
twitter.updateStatus(status);
|
||||
}
|
||||
catch (Exception e) {
|
||||
@@ -173,10 +176,67 @@ public class Twitter4jTemplate implements TwitterOperations{
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getFriends(String screenName) {
|
||||
throw new NotImplementedException("This method is not implemented since it is not used by any of the " +
|
||||
"Spring Integration adapters. It exists strictly for being compliant with Spring Social interface untill" +
|
||||
"migration to use Spring Social is complete in Spring Integration 2.1.0");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void retweet(long tweetId) {
|
||||
throw new NotImplementedException("This method is not implemented since it is not used by any of the " +
|
||||
"Spring Integration adapters. It exists strictly for being compliant with Spring Social interface untill" +
|
||||
"migration to use Spring Social is complete in Spring Integration 2.1.0");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SearchResults search(String query) {
|
||||
Assert.hasText(query, "'query' must not be null");
|
||||
Query q = new Query(query);
|
||||
return this.search(q);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SearchResults search(String query, int page, int pageSize) {
|
||||
Assert.hasText(query, "'query' must not be null");
|
||||
Query q = new Query(query);
|
||||
q.setPage(page);
|
||||
return this.search(q);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SearchResults search(String query, int page, int resultsPerPage,
|
||||
int sinceId, int maxId) {
|
||||
Assert.hasText(query, "'query' must not be null");
|
||||
Query q = new Query(query);
|
||||
q.setPage(page);
|
||||
q.setSinceId(sinceId);
|
||||
q.setMaxId(maxId);
|
||||
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(), false);
|
||||
return results;
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new TwitterOperationException("Failed to send Status update. ", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<Tweet> buildTweetsFromTwitterResponses(List<?> responses){
|
||||
List<Tweet> tweets = new LinkedList<Tweet>();
|
||||
if (responses != null){
|
||||
@@ -184,9 +244,15 @@ public class Twitter4jTemplate implements TwitterOperations{
|
||||
if (response instanceof Status){
|
||||
tweets.add(this.buildTweetFromStatus((Status) response));
|
||||
}
|
||||
else {
|
||||
else if (response instanceof DirectMessage) {
|
||||
tweets.add(this.buildTweetFromDm((DirectMessage) response));
|
||||
}
|
||||
else if (response instanceof twitter4j.Tweet){
|
||||
tweets.add(this.buildTweetFromT4jTweet((twitter4j.Tweet) response));
|
||||
}
|
||||
else {
|
||||
throw new TwitterOperationException("Unsupported response type: " + response.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
return tweets;
|
||||
@@ -215,4 +281,17 @@ public class Twitter4jTemplate implements TwitterOperations{
|
||||
tweet.setText(status.getText());
|
||||
return tweet;
|
||||
}
|
||||
|
||||
private Tweet buildTweetFromT4jTweet(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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,14 +20,95 @@ 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();
|
||||
|
||||
/**
|
||||
* Retrieves a list of users that the given user follows.
|
||||
*
|
||||
* @param screenName
|
||||
* The user's Twitter screen name
|
||||
* @return a list of user screen names
|
||||
*/
|
||||
List<String> getFriends(String screenName);
|
||||
|
||||
/**
|
||||
* Updates the user's status.
|
||||
*
|
||||
* @param status
|
||||
* The status message
|
||||
*
|
||||
*/
|
||||
void updateStatus(String status);
|
||||
|
||||
/**
|
||||
* Posts a retweet of an existing tweet.
|
||||
*
|
||||
* @param tweetId
|
||||
* The ID of the tweet to be retweeted
|
||||
*
|
||||
* @throws SocialException
|
||||
* if an error response is received from Twitter
|
||||
*/
|
||||
void retweet(long tweetId);
|
||||
|
||||
/**
|
||||
* Searches Twitter, returning the first 50 matching {@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 page
|
||||
* The page to return
|
||||
* @param pageSize
|
||||
* The number of {@link Tweet}s per page
|
||||
*
|
||||
* @return a {@link SearchResults} containing {@link Tweet}s
|
||||
*
|
||||
*/
|
||||
SearchResults search(String query, int page, int pageSize);
|
||||
|
||||
/**
|
||||
* Searches Twitter, returning a specific page out of the complete set of
|
||||
* results. Results are filtered to those whose ID falls between sinceId and
|
||||
* maxId
|
||||
*
|
||||
* @param query
|
||||
* The search query string
|
||||
* @param page
|
||||
* The page to return
|
||||
* @param pageSize
|
||||
* The number of {@link Tweet}s per page
|
||||
* @param sinceId
|
||||
* The minimum {@link Tweet} ID to return in the results
|
||||
* @param maxId
|
||||
* The maximum {@link Tweet} ID to return in the results
|
||||
*
|
||||
* @return a {@link SearchResults} containing {@link Tweet}s
|
||||
*/
|
||||
SearchResults search(String query, int page, int resultsPerPage, int sinceId, int maxId);
|
||||
|
||||
List<Tweet> getDirectMessages();
|
||||
|
||||
List<Tweet> getDirectMessages(long sinceId);
|
||||
@@ -43,8 +124,9 @@ public interface TwitterOperations {
|
||||
void sendDirectMessage(String userName, String text);
|
||||
|
||||
void sendDirectMessage(int userId, String text);
|
||||
|
||||
void updateStatus(Tweet status);
|
||||
|
||||
|
||||
/**
|
||||
* Temporary method. Should be removed one migrated to Spring Social
|
||||
*/
|
||||
Twitter getUnderlyingTwitter();
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.integration.twitter.outbound;
|
||||
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessageHandlingException;
|
||||
import org.springframework.integration.twitter.core.Tweet;
|
||||
import org.springframework.integration.twitter.core.TwitterOperations;
|
||||
|
||||
@@ -35,8 +36,18 @@ public class TimelineUpdateSendingMessageHandler extends AbstractOutboundTwitter
|
||||
|
||||
@Override
|
||||
protected void handleMessageInternal(Message<?> message) throws Exception {
|
||||
Tweet tweet = this.outboundMaper.fromMessage(message);
|
||||
this.twitter.updateStatus(tweet);
|
||||
Object payload = message.getPayload();
|
||||
String statusText = null;
|
||||
if (payload instanceof Tweet){
|
||||
statusText = ((Tweet)payload).getText();
|
||||
}
|
||||
else if (payload instanceof String){
|
||||
statusText = (String) payload;
|
||||
}
|
||||
else {
|
||||
throw new MessageHandlingException(message, "Unsupported payload type '" + payload.getClass().getName() + "'");
|
||||
}
|
||||
this.twitter.updateStatus(statusText);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -105,10 +105,7 @@ public class Twitter4jTemplateTests {
|
||||
|
||||
@Test
|
||||
public void testUpdateStatus() throws Exception{
|
||||
Tweet tweet = new Tweet();
|
||||
tweet.setToUserId((long) 123);
|
||||
tweet.setText("writing twitter test");
|
||||
template.updateStatus(tweet);
|
||||
template.updateStatus("writing twitter test");
|
||||
verify(twitter, times(1)).updateStatus(Mockito.any(StatusUpdate.class));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ public class TimelineUpdateSendingMessageHandlerTests {
|
||||
Tweet tweet = new Tweet();
|
||||
tweet.setText("writing twitter tests");
|
||||
handler.handleMessage(new GenericMessage(tweet));
|
||||
verify(twitterOperations, times(1)).updateStatus(Mockito.any(Tweet.class));
|
||||
verify(twitterOperations, times(1)).updateStatus(Mockito.any(String.class));
|
||||
verify(twitter, times(1)).updateStatus(Mockito.any(StatusUpdate.class));
|
||||
}
|
||||
@Test
|
||||
@@ -75,7 +75,7 @@ public class TimelineUpdateSendingMessageHandlerTests {
|
||||
.setHeader(TwitterHeaders.DISPLAY_COORDINATES, true)
|
||||
.build();
|
||||
handler.handleMessage(message);
|
||||
verify(twitterOperations, times(1)).updateStatus(Mockito.any(Tweet.class));
|
||||
verify(twitterOperations, times(1)).updateStatus(Mockito.any(String.class));
|
||||
verify(twitter, times(1)).updateStatus(Mockito.any(StatusUpdate.class));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user