/*
* TwitterApi.java
*
* Copyright (C) 2005-2010 Tommi Laukkanen
* http://www.substanceofcode.com
*
* 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 com.substanceofcode.twitter;
import com.substanceofcode.twitter.model.Status;
import com.substanceofcode.utils.HttpUtil;
import com.substanceofcode.utils.Log;
import com.substanceofcode.utils.StringUtil;
import java.io.IOException;
import java.util.Calendar;
import java.util.Vector;
/**
* TwitterApi
*
* @author Tommi Laukkanen (tlaukkanen at gmail dot com)
*/
public class TwitterApi {
private String username;
private String password;
private static final String PUBLIC_TIMELINE_URL = "http://www.twitter.com/statuses/public_timeline.xml";
private static final String HOME_TIMELINE_URL = "http://api.twitter.com/1/statuses/home_timeline.xml"; // Old: "http://www.twitter.com/statuses/friends_timeline.xml";
private static final String USER_TIMELINE_URL = "http://api.twitter.com/1/statuses/user_timeline.xml";
private static final String RESPONSES_TIMELINE_URL = "http://api.twitter.com/1/statuses/mentions.xml";
private static final String STATUS_UPDATE_URL = "http://api.twitter.com/1/statuses/update.xml"; // "http://twitter.com/statuses/update.xml";
private static final String DIRECT_TIMELINE_URL = "http://api.twitter.com/1/direct_messages.xml";
private static final String FRIENDS_URL = "http://api.twitter.com/1/statuses/friends_timeline.xml";
private static final String FAVORITE_TIMELINE_URL = "http://api.twitter.com/1/favorites.xml";
private static final String FAVORITE_CREATE_URL = "http://api.twitter.com/1/favorites/create/";
private static final String FAVORITE_DESTROY_URL = "http://api.twitter.com/1/favorites/destroy/";
private static final String FRIENDSHIPS_CREATE_URL = "http://api.twitter.com/1/friendships/create/";
private static final String FRIENDSHIPS_DESTROY_URL = "http://api.twitter.com/1/friendships/destroy/";
private static final String SEARCH_URL = "http://search.twitter.com/search.atom?rpp=20&q=";
private static final String RETWEETS_OF_ME_URL = "http://api.twitter.com/1/statuses/retweets_of_me.xml";
private static final String LISTS_URL = "http://api.twitter.com/1/@USERNAME@/lists.xml";
private static final String LIST_STATUSES_URL = "http://api.twitter.com/1/@USERNAME@/lists/@LIST@/statuses.xml";
// XAuth specific parameters
private static final String OAUTH_REQUEST_TOKEN_URL = "https://api.twitter.com/oauth/request_token";
private static final String OAUTH_ACCESS_TOKEN_URL = "https://api.twitter.com/oauth/access_token";
private static final String OAUTH_AUTHORIZE_URL = "https://api.twitter.com/oauth/authorize";
private static boolean isAuthenticated = false;
private static Status authErrStatus = null;
private static XAuth xauth;
/** Creates a new instance of TwitterApi */
public TwitterApi() {
}
public void bypassAuthorization(String token, String tokenSecret) {
if(token!=null && token.length()>0) {
xauth = new XAuth(username, password);
xauth.setTokenAndSecret(token, tokenSecret);
isAuthenticated = true;
} else {
isAuthenticated = false;
}
}
public boolean authorize() {
if(isAuthenticated) {
return true;
}
String token = "";
try {
System.out.println("Trying to authenticate");
xauth = new XAuth(username, password);
token = xauth.xAuthWebRequest(false, OAUTH_ACCESS_TOKEN_URL, null, null);
System.out.println("ACCESS TOKEN: " + token);
if(token.indexOf("oauth_token_secret")>0) {
// Success
String oauthToken = HttpUtil.parseParameter(token, "oauth_token");
String oauthTokenSecret = HttpUtil.parseParameter(token, "oauth_token_secret");
xauth.setTokenAndSecret(oauthToken, oauthTokenSecret);
isAuthenticated = true;
authErrStatus = null;
return true;
} else {
// Failure
authErrStatus = new Status("Twitter", "Couldn't find OAuth token from response: " + token, null, "");
isAuthenticated = false;
return false;
}
} catch (Exception ex) {
authErrStatus = new Status("Twitter", "Couldn't authenticate. Exception: " + ex.getMessage(), null, "");
isAuthenticated = false;
return false;
}
}
public String followUser(Status status) throws Exception {
try {
NullParser parser = new NullParser();
String url = FRIENDSHIPS_CREATE_URL + status.getScreenName() + ".xml";
xauth.xAuthWebRequest(true, url, null, parser);
//HttpUtil.doPost( url, parser );
return parser.getResponse();
} catch(Exception ex) {
throw ex;
}
}
public String unfollowUser(Status status) throws Exception {
try {
NullParser parser = new NullParser();
String url = FRIENDSHIPS_DESTROY_URL + status.getScreenName() + ".xml";
xauth.xAuthWebRequest(true, url, null, parser);
return parser.getResponse();
} catch(Exception ex) {
throw ex;
}
}
public Status markAsFavorite(Status status) {
try {
StatusFeedParser parser = new StatusFeedParser();
String url = FAVORITE_CREATE_URL + status.getId() + ".xml";
xauth.xAuthWebRequest(true, url, null, parser);
//HttpUtil.doPost( url, parser );
Vector statuses = parser.getStatuses();
if(statuses!=null && statuses.isEmpty()==false) {
return (Status)statuses.elementAt(0);
}
} catch(Exception ex) {
return new Status(
"Twim",
"Error while marking status as favorite: " + ex.getMessage(),
Calendar.getInstance().getTime(),
"0");
}
return null;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
/**
* Request direct messages from Twitter API
* @return Vector containing direct messages.
*/
public Vector requestDirectTimeline() {
return requestTimeline( DIRECT_TIMELINE_URL );
}
/**
* Request favorite tweets from Twitter API.
* @return Vector containing favorite tweets.
*/
public Vector requestFavouriteTimeline() {
return requestTimeline(FAVORITE_TIMELINE_URL);
}
/**
* Request home (following) timeline from Twitter API.
* @return Vector containing StatusEntry items.
*/
public Vector requestHomeTimeline(int page) {
String url = HOME_TIMELINE_URL;
if(page>1) {
url += "?page=" + page;
}
return requestTimeline( url );
}
/**
* Request public timeline from Twitter API.
* @return Vector containing StatusEntry items.
*/
public Vector requestUserTimeline() {
return requestTimeline(USER_TIMELINE_URL);
}
/**
* Request public timeline from Twitter API.
* @return Vector containing StatusEntry items.
*/
public Vector requestPublicTimeline() {
return requestTimeline(PUBLIC_TIMELINE_URL);
}
public Vector requestRetweetsOfMe(int page) {
String url = RETWEETS_OF_ME_URL;
if(page>1) {
url += "?page=" + page;
}
return requestTimeline( url );
}
/**
* Request responses timeline from Twitter API.{
* @return Vector containing StatusEntry items.
*/
public Vector requestResponsesTimeline() {
return requestTimeline(RESPONSES_TIMELINE_URL);
}
public Status updateStatus(String status) {
try {
if(authorize()==false) {
if(authErrStatus!=null) {
return authErrStatus;
}
}
StatusFeedParser parser = new StatusFeedParser();
String url = STATUS_UPDATE_URL;
QueryParameter[] params = new QueryParameter[] {
new QueryParameter("status", status),
new QueryParameter("source", "twim")
};
// "?status=" + URLUTF8Encoder.encode(status) +
// "&source=twim";
xauth.xAuthWebRequest(true, STATUS_UPDATE_URL, params, parser);
//HttpUtil.doPost( url, parser );
Vector statuses = parser.getStatuses();
if(statuses!=null && statuses.isEmpty()==false && status.startsWith("d ")==false) {
return (Status)statuses.elementAt(0);
}
} catch(Exception ex) {
return new Status(
"Twim",
"Error while updating status: " + ex.getMessage(),
Calendar.getInstance().getTime(),
"0");
}
return null;
}
/**
* Request friends from Twitter API.
* @return Vector containing friends.
*/
public Vector requestFriendsTimeline() throws IOException, Exception{
Vector entries = new Vector();
authorize();
try {
HttpUtil.setBasicAuthentication("", "");
StatusFeedParser parser = new StatusFeedParser();
xauth.xAuthWebRequest(false, FRIENDS_URL, null, parser);
//HttpUtil.doGet(FRIENDS_URL, parser);
entries = parser.getStatuses();
} catch (IOException ex) {
throw new IOException("Error in TwitterApi.requestFriends: "
+ ex.getMessage());
} catch (Exception ex) {
throw new Exception("Error in TwitterApi.requestFriends: "
+ ex.getMessage());
}
return entries;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
private Vector requestTimeline(String timelineUrl) {
Vector entries = new Vector();
if(authorize()==false) {
if(authErrStatus!=null) {
entries.addElement(authErrStatus);
return entries;
}
}
try {
boolean retry = false;
do {
//HttpUtil.setBasicAuthentication(username, password);
HttpUtil.setBasicAuthentication("", "");
StatusFeedParser parser = new StatusFeedParser();
if(timelineUrl.equals(DIRECT_TIMELINE_URL)) {
parser.setDirect(true);
}
xauth.xAuthWebRequest(false, timelineUrl, null, parser);
//HttpUtil.doGet(timelineUrl, parser);
int lastResponseCode = HttpUtil.getLastResponseCode();
entries = parser.getStatuses();
if(entries.isEmpty() && parser.isReallyEmpty()==false) {
entries.addElement(
new Status("Twitter", "No statuses. API response from " +
timelineUrl + " (" + lastResponseCode + "): " +
HttpUtil.getHeaders() + " " +
parser.getRawData(),
Calendar.getInstance().getTime(), ""));
retry = !retry;
} else if(entries.isEmpty() && parser.isReallyEmpty()==true) {
entries.addElement(
new Status("Twitter", "No Tweets found.",
Calendar.getInstance().getTime(), ""));
} else {
retry = false;
}
} while(retry);
} catch (IOException ex) {
entries.addElement(
new Status("Twitter", "Error occured. Please check " +
"your connection or username and password.",
Calendar.getInstance().getTime(), ""));
entries.addElement(
new Status("Twitter", "StackTrace: " + ex.toString(),
Calendar.getInstance().getTime(), ""));
ex.printStackTrace();
} catch (Exception ex) {
entries.addElement(
new Status("Twitter", "API exception: " + ex.toString(),
Calendar.getInstance().getTime(), ""));
}
return entries;
}
public Status markAsUnfavorite(Status status) {
try {
StatusFeedParser parser = new StatusFeedParser();
String url = FAVORITE_DESTROY_URL + status.getId() + ".xml";
xauth.xAuthWebRequest(true, url, null, parser);
//HttpUtil.doPost( url, parser );
Vector statuses = parser.getStatuses();
if(statuses!=null && statuses.isEmpty()==false) {
return (Status)statuses.elementAt(0);
}
} catch(Exception ex) {
return new Status(
"Twim",
"Error while marking status as unfavorite: " + ex.getMessage(),
Calendar.getInstance().getTime(),
"0");
}
return null;
}
public Vector search(String query, int page) throws Exception {
try {
SearchResultsParser parser = new SearchResultsParser();
String url = SEARCH_URL + StringUtil.urlEncode(query) + "&page=" + page;
Log.debug("URL: " + url);
HttpUtil.doPost( url, parser );
Vector statuses = parser.getStatuses();
return statuses;
} catch(Exception ex) {
throw new Exception("Error while searching tweets: " + ex.getMessage());
}
}
public Vector requestLists() throws Exception {
authorize();
Vector entries = new Vector();
try {
ListsParser parser = new ListsParser();
String url = StringUtil.replace(LISTS_URL, "@USERNAME@", username);
xauth.xAuthWebRequest(false, url, null, parser);
//HttpUtil.doGet(url, parser);
entries = parser.getUserLists();
} catch (IOException ex) {
throw new IOException("Error in TwitterApi.requestLists: "
+ ex.getMessage());
} catch (Exception ex) {
throw new Exception("Error in TwitterApi.requestLists: "
+ ex.getMessage());
}
return entries;
}
public Vector requestListStatuses(String listName) {
String url = StringUtil.replace(LIST_STATUSES_URL, "@LIST@", StringUtil.urlEncode(listName));
url = StringUtil.replace(url, "@USERNAME@", username);
System.out.println("Loading custom URL: " + url);
return requestTimeline(url);
}
void resetToken() {
xauth.setTokenAndSecret("", "");
isAuthenticated = false;
}
}