diff --git a/spring-integration-twitter/src/main/java/org/springframework/integration/twitter/core/SearchResults.java b/spring-integration-twitter/src/main/java/org/springframework/integration/twitter/core/SearchResults.java new file mode 100644 index 0000000000..3d39534b49 --- /dev/null +++ b/spring-integration-twitter/src/main/java/org/springframework/integration/twitter/core/SearchResults.java @@ -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 tweets; + private long maxId; + private long sinceId; + private boolean lastPage; + + public SearchResults(List 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 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 true if this is the last page of matching + * {@link Tweet}s; false if there are more pages that follow + * this one. + */ + public boolean isLastPage() { + return lastPage; + } +} diff --git a/spring-integration-twitter/src/main/java/org/springframework/integration/twitter/core/Twitter4jTemplate.java b/spring-integration-twitter/src/main/java/org/springframework/integration/twitter/core/Twitter4jTemplate.java index e37e2e6ecf..7dafbf34be 100644 --- a/spring-integration-twitter/src/main/java/org/springframework/integration/twitter/core/Twitter4jTemplate.java +++ b/spring-integration-twitter/src/main/java/org/springframework/integration/twitter/core/Twitter4jTemplate.java @@ -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 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 t4jTweets = result.getTweets(); + List 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 buildTweetsFromTwitterResponses(List responses){ List tweets = new LinkedList(); 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; + } } diff --git a/spring-integration-twitter/src/main/java/org/springframework/integration/twitter/core/TwitterOperations.java b/spring-integration-twitter/src/main/java/org/springframework/integration/twitter/core/TwitterOperations.java index e001582cc3..a6bc676cf6 100644 --- a/spring-integration-twitter/src/main/java/org/springframework/integration/twitter/core/TwitterOperations.java +++ b/spring-integration-twitter/src/main/java/org/springframework/integration/twitter/core/TwitterOperations.java @@ -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 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 getDirectMessages(); List 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(); } diff --git a/spring-integration-twitter/src/main/java/org/springframework/integration/twitter/outbound/TimelineUpdateSendingMessageHandler.java b/spring-integration-twitter/src/main/java/org/springframework/integration/twitter/outbound/TimelineUpdateSendingMessageHandler.java index 6f75ed630a..c0f1c36847 100644 --- a/spring-integration-twitter/src/main/java/org/springframework/integration/twitter/outbound/TimelineUpdateSendingMessageHandler.java +++ b/spring-integration-twitter/src/main/java/org/springframework/integration/twitter/outbound/TimelineUpdateSendingMessageHandler.java @@ -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); } } diff --git a/spring-integration-twitter/src/test/java/org/springframework/integration/twitter/core/Twitter4jTemplateTests.java b/spring-integration-twitter/src/test/java/org/springframework/integration/twitter/core/Twitter4jTemplateTests.java index 021cc1c4d8..7ccf455005 100644 --- a/spring-integration-twitter/src/test/java/org/springframework/integration/twitter/core/Twitter4jTemplateTests.java +++ b/spring-integration-twitter/src/test/java/org/springframework/integration/twitter/core/Twitter4jTemplateTests.java @@ -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)); } } diff --git a/spring-integration-twitter/src/test/java/org/springframework/integration/twitter/outbound/TimelineUpdateSendingMessageHandlerTests.java b/spring-integration-twitter/src/test/java/org/springframework/integration/twitter/outbound/TimelineUpdateSendingMessageHandlerTests.java index 2da212438e..26c1d0917f 100644 --- a/spring-integration-twitter/src/test/java/org/springframework/integration/twitter/outbound/TimelineUpdateSendingMessageHandlerTests.java +++ b/spring-integration-twitter/src/test/java/org/springframework/integration/twitter/outbound/TimelineUpdateSendingMessageHandlerTests.java @@ -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)); } }