Show Tweets with HST and Twitter4J
As you may have noticed, my five latest Tweets show up on my site. In this blog I'll explain how you can easily add such a block to your HST site.
For the Twitter component I've used Twitter4J to retrieve my latest tweets. The first step is to add its dependency to your CMS pom:
<dependency> <groupId>org.twitter4j</groupId> <artifactId>twitter4j-core</artifactId> <version>[2.1,)</version> </dependency>
Then create your TwitterComponent that extends org.hippoecm.hst.component.support.bean.BaseHstComponent. In your TwitterComponent add a doBeforeRender method that will fetch your latest updates. The quick (and a bit dirty) way is to authenticate using a Twitter username and password. Twitter4J also supports using oAuth which you may prefer over storing your Twitter credentials.
First get a Twitter instance with your credentials (wil be deprecated see update at the end of this article):
Twitter twitter = new TwitterFactory().getInstance([username], [password]);
Then get your Tweets and ReTweets. Twitter does not return a combined list of Tweets and ReTweets because of backwards compatibility so you'll have to combine them yourself. You probably want to show the newest first so you'll have to use a descending sort order based on the ID of the Status.
try {
List<Status> statuses = twitter.getUserTimeline();
List<Status> retweets = twitter.getRetweetedByMe();
statuses.addAll(retweets);
Set<Status> allStatuses = new TreeSet<Status>(Collections.reverseOrder());
allStatuses.addAll(statuses);
allStatuses.addAll(retweets);
if (!allStatuses.isEmpty()) {
request.setAttribute("statuses", allStatuses);
}
} catch (TwitterException e) {
log.warn("Error getting Twitter status updates", e);
}
To display the 5 newest (Re)Tweets, use this in your JSP (don't forget to add the taglibs):
<ul>
<c:forEach items="${statuses}" var="status" begin="0" end="4">
<li>
<c:choose>
<c:when test="${status.retweet}">
RT ${status.retweetedStatus.user.screenName}: ${status.retweetedStatus.text}<br />
Retweeted at
<a href="http://twitter.com/${status.retweetedStatus.user.screenName}/status/${status.retweetedStatus.id}" rel="external">
<fmt:formatDate value="${status.createdAt}" pattern="d MMM H:mm"/></a>
</c:when>
<c:otherwise>
${status.text}<br />
<a href="http://twitter.com/${status.user.screenName}/status/${status.id}" rel="external">
<fmt:formatDate value="${status.createdAt}" pattern="d MMM H:mm"/></a>
</c:otherwise>
</c:choose>
</li>
</c:forEach>
</ul>
Note: Twitter4J does not have a caching mechanism yet. Twitter allows you to do 150 API calls per hour (excluding posting updates). If you exceed that limit, it will return a 400 (bad request) instead of your latest (Re)Tweets.
Update about authentication (22-07-2010)
I totally overlooked the warning by Twitter that the basic authentication is going to be shut down from August 16 in favour of oAuth. If you need a quick & dirty way to generate your Autorization secrets, register your application (choose for Application Type client) and read this blog to generate your AccesToken. Then you can get a Twitter instance with:
AccessToken accessToken = new AccessToken([token],[tokenSecret]); Twitter twitter= new TwitterFactory().getOAuthAuthorizedInstance([consumerKey], [consumerSecret], accessToken);
2 comments
Jasha said
Storing the Tweets in a tree in the repo is something I've certainly thought about but haven't implemented yet. I'd be very happy if my site gets that amount of traffic :)
You could save those tweets in the repo with a timestamp of the last time the HST has contacted Twitter and use that to define if the HST has to contact Twitter or not. Serving the Tweets from the repository has another benefit: you're not depending on the availability of Twitter which is not the most reliable service on the internet.
For serving 25 accounts on a website I think you can add all those accounts to a list and then get all the Tweets for that list using Twitter#getUserList().
This showed the Tweets for my lists
Paging paging = new Paging(1, 25); PagableResponseList<UserList> userLists = twitter.getUserLists(username, -1); for (UserList userList : userLists) { System.out.println("List " + userList.getId() + " " + userList.getFullName()); ResponseList<Status> responseList = twitter.getUserListStatuses(username, userList.getId(), paging); for (Status s : responseList) { System.out.println(s.getUser().getName() + " " + s.getText()); } }G Berkouwer said
Interesting! Only the problem of max 150 api calls is very real for big websites. Would it be better to store lets say the content of e.g. the last 3 tweets, and serve those? Then you would maybe get the last three every 10 minutes or so. This would probably give you more performance?
And what to do if you want to show tweets of lets say 25 twitter-acounts on 1 website? That makes 25 calls every 10 minutes so there goes your api-limit!
Any thoughts about that?