/*
* Copyright 2010 VoidSearch.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.voidsearch.data.provider.facebook;
import com.voidsearch.data.provider.facebook.objects.*;
import com.voidsearch.voidbase.client.VoidBaseHttpClient;
import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONTokener;
import java.io.StringReader;
import java.net.URLEncoder;
import java.util.LinkedList;
public class SimpleGraphAPIClient extends VoidBaseHttpClient {
private static String GRAPH_API_HOST = "https://graph.facebook.com/";
private static String ACCESS_TOKEN_PARAM = "access_token";
private static long DEFAULT_QUERY_DELAY = 5000;
private String accessToken;
private long queryDelay;
private long queryTimer = System.currentTimeMillis();
public SimpleGraphAPIClient(String accessToken, long queryDelay) {
this.accessToken = accessToken;
this.queryDelay = queryDelay;
}
public SimpleGraphAPIClient(String accessToken) {
this.accessToken = accessToken;
this.queryDelay = DEFAULT_QUERY_DELAY;
}
/**
* set millisecond delay between queries
*
* @param delayTime
*/
public void setQueryDelay(long delayTime) {
this.queryDelay = delayTime;
}
/**
* get list of friends for current authenticated user
*
* @return
* @throws Exception
*/
public LinkedList<FacebookUser> getFriends() throws Exception {
return getFriends("me");
}
/**
* get list of friends corresponding to specific user
*
* @param user
* @return
* @throws Exception
*/
public LinkedList<FacebookUser> getFriends(String user) throws Exception {
return this.<FacebookUser>getResultList(user,"friends");
}
/**
* get all likes for particular user
*
* @param user
* @return
* @throws Exception
*/
public LinkedList<LikedEntry> getLikes(String user) throws Exception {
return this.<LikedEntry>getResultList(user,"likes");
}
/**
* get all photos for single user
*
* @param user
* @return
* @throws Exception
*/
public LinkedList<PhotoEntry> getPhotos(String user) throws Exception {
return this.<PhotoEntry>getResultList(user,"photos");
}
/**
* get all groups for single user
*
* @param user
* @return
* @throws Exception
*/
public LinkedList<GroupEntry> getGroups(String user) throws Exception {
return this.<GroupEntry>getResultList(user,"groups");
}
/**
* get all news events for single user
*
* @param user
* @return
* @throws Exception
*/
public LinkedList<NewsEntry> getNews(String user) throws Exception {
return this.<NewsEntry>getResultList(user,"home");
}
/**
* get paginated list of results
*
* @param user
* @param feedName
* @param <T>
* @return
* @throws Exception
*/
private <T> LinkedList<T> getResultList(String user, String feedName) throws Exception {
LinkedList<T> results = new LinkedList<T>();
String query = GRAPH_API_HOST + user + "/" + feedName;
boolean hasMore = true;
while(hasMore == true) {
JSONObject response = getResponse(query);
JSONArray resultArray = response.getJSONArray("data");
loadResults(results, resultArray, feedName);
if (hasMore(response)) {
String nextQuery = getNextPageURL(response);
if (!nextQuery.equals(query)) {
query = nextQuery;
} else {
hasMore = false;
}
} else {
hasMore = false;
}
}
return results;
}
/**
* load result list from json response for given feed
*
* @param results
* @param resultArray
* @param feedName
* @param <T>
* @throws Exception
*/
private <T> void loadResults(LinkedList<T> results, JSONArray resultArray, String feedName) throws Exception {
for (int i = 0; i < resultArray.length(); i++) {
results.add((T)GraphObjectFactory.getObject(feedName, (JSONObject)resultArray.get(i)));
}
}
/**
* get "data" entry fron JSON response
*
* @param query
* @return
* @throws Exception
*/
private JSONArray getDataArray(String query) throws Exception {
JSONObject response = getResponse(query);
return response.getJSONArray("data");
}
/**
* get response from Graph API
*
* @param query
* @return
* @throws Exception
*/
private JSONObject getResponse(String query) throws Exception {
if (!(query.contains("?") && query.contains(ACCESS_TOKEN_PARAM))) {
query += "?" + ACCESS_TOKEN_PARAM + "=" + URLEncoder.encode(accessToken);
}
// force query delay interval
long lastQueryElapsed = getQueryDelay();
if (lastQueryElapsed < queryDelay) {
Thread.sleep(queryDelay - lastQueryElapsed);
}
resetQueryTimer();
byte[] response = get(query);
return new JSONObject(new JSONTokener(new StringReader(new String(new String(response)))));
}
/**
* get elapsed time since last query
*
* @return
*/
private long getQueryDelay() {
return System.currentTimeMillis() - queryTimer;
}
/**
* reset internal query delay counter
*
*/
private void resetQueryTimer() {
queryTimer = System.currentTimeMillis();
}
/**
* check whether return object has pagination
*
* @param object
* @return
*/
private boolean hasMore(JSONObject object) throws Exception {
return object.has("paging");
}
/**
* get next page url
*
* @param object
* @return
* @throws Exception
*/
private String getNextPageURL(JSONObject object) throws Exception {
JSONObject paging = (JSONObject)object.get("paging");
return (String)paging.get("next");
}
}