/*--------------------------------------------------------------------------+ | Copyright (c) 2006 Facebook, Inc. | | All rights reserved. | | | | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the following conditions | | are met: | | | | 1. Redistributions of source code must retain the above copyright | | notice, this list of conditions and the following disclaimer. | | 2. Redistributions in binary form must reproduce the above copyright | | notice, this list of conditions and the following disclaimer in the | | documentation and/or other materials provided with the distribution. | | | | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | +---------------------------------------------------------------------------+ | For help with this library, contact api-help@facebook.com | +--------------------------------------------------------------------------*/ package com.moochspot.util; import java.io.IOException; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import com.google.code.facebookapi.FacebookException; import com.google.code.facebookapi.FacebookJsonRestClient; import com.google.code.facebookapi.ProfileField; /** * Wrapper around the Facebook API to encapsulate operations on friends. * This allows application code to deal with a couple of high-level objects, * {@link FacebookFriend} (representing information about a * single friend) and {@link FacebookFriends} (representing a * collection of friends). *

* To customize which fields are fetched from Facebook, first edit the * {@link FacebookFriend} class to add whatever fields you need. * Then modify this class's {@link #extractFriend(Node) * extractFriend()} method (and optionally {@link #getFriend(String) * getFriend()} to extract the new fields. */ public class FacebookApi { public static String DEFAULT_API_URL = "http://api.facebook.com/restserver.php"; private Logger _log = Logger.getLogger(getClass().getName()); protected FacebookJsonRestClient _client; /** * Constructs a new Facebook API wrapper. * * @param serverUrl * URL of API server to connect to. * @param sessionKey * Session key as returned by facebook.auth.getSession (which * is wrapped by this class's {@link #fetchCredentials(String) * fetchCredentials()} method). Null if this wrapper should not * be associated with a session, e.g. because it is being used to handle * a new login. */ public FacebookApi(String serverUrl, String sessionKey) { try { _client = new FacebookJsonRestClient(serverUrl, Constants.FACEBOOK_KEY, Constants.FACEBOOK_SHARED_SECRET, sessionKey); } catch (MalformedURLException e) { _log.severe("Bad server URL " + serverUrl); throw new RuntimeException(e); } } /** * Constructs a new Facebook API wrapper. * * @param sessionKey * Session key as returned by facebook.auth.getSession (which * is wrapped by this class's {@link #fetchCredentials(String) * fetchCredentials()} method). Null if this wrapper should not * be associated with a session, e.g. because it is being used to handle * a new login. */ public FacebookApi(String sessionKey) { this(DEFAULT_API_URL, sessionKey); } /** * Fetches the user ID for a session key. * * @param authToken * Authentication token as passed in on query string after redirection * from Facebook login page. * @return null if the session key was invalid or Facebook couldn't be * contacted. */ public FacebookCredentials fetchCredentials(String authToken) { if (authToken == null) return null; FacebookCredentials creds = new FacebookCredentials(); Document document = null; try { List params = new ArrayList(); params.add("auth_token=" + authToken); creds.setSessionKey(_client.auth_getSession(authToken)); creds.setUid(_client.getCacheUserId().toString()); return creds; } catch (Exception e) { _log.log(Level.SEVERE, "Can't fetch session data for " + authToken, e); if (document != null) { _log.info(document.toString()); } return null; } } /** * Returns specific pieces of friend info for a specific user. * * @param userId * Facebook user ID of the friend whose information is to be returned. * @param fields * Comma-delimited list of fields to request. */ public FacebookFriend getFriend(String userId, Set fields) { List uids = new ArrayList(1); uids.add(userId); try { FacebookFriends friends = getInfo(uids, fields); if (friends.getAll().size() == 0) return null; return friends.getAll().first(); } catch (Exception e) { _log.log(Level.SEVERE, "Can't look up user " + userId, e); return null; } } /** * Returns all the defined friend info for a specific user. */ public FacebookFriend getFriend(String userId) { Set fields = new HashSet(2); fields.add(ProfileField.FIRST_NAME); fields.add(ProfileField.NAME); return getFriend(userId, fields); } /** * Returns a list of selected pieces of information about the user's friends. * * @param fields * Comma-delimited list of fields to query from Facebook. */ public FacebookFriends getFriends(Set fields) { try { return getInfo(getFriendIds(), fields); } catch (Exception e) { _log.log(Level.SEVERE, "Can't look up friends", e); return null; } } /** * Returns a list of the user's friends with full names. */ public FacebookFriends getFriendsName() { Set fields = new HashSet(1); fields.add(ProfileField.NAME); return getFriends(fields); } /** * Returns a list of the user's friends' Facebook user IDs. */ public Collection getFriendIds() throws FacebookException, IOException { Collection userIds = new LinkedList(); JSONArray friends = _client.friends_get(); if (friends == null || friends.length() == 0) { return userIds; } /* Walk the list of result elements; each one's contents is a user ID. */ for (int i = 0; i < friends.length(); i++) { try { userIds.add(friends.getString(i)); } catch (JSONException e) { _log.warning("Can't fetch friend " + i + " from list"); throw new IOException("friend list can't be extracted"); } } return userIds; } /** * Returns information for a list of Facebook user IDs. * * @param userIds * User IDs to fetch information for. All these users must be friends of * the current user. * @param fieldList * List of fields to fetch. */ public FacebookFriends getInfo(Collection userIds, Set fields) throws FacebookException, IOException { Collection longUserIds = new ArrayList(userIds.size()); for (String uid : userIds) { longUserIds.add(Long.valueOf(uid)); } Object result = _client.users_getInfo(longUserIds, fields); if (result == null) { return new FacebookFriends(); } if (result instanceof JSONArray) { return extractFriendsFromGetInfo((JSONArray) result); } throw new IOException("Got unexpected response: " + result.toString()); } /** * Extracts a FacebookFriends object from the results of a * "facebook.users.getInfo" API call. */ private FacebookFriends extractFriendsFromGetInfo(JSONArray result) { FacebookFriends friends = new FacebookFriends(); for (int i = 0; i < result.length(); i++) { try { JSONObject element = result.getJSONObject(i); friends.add(extractFriend(element)); } catch (JSONException e) { _log.warning("Can't extract element from JSON array"); } } return friends; } /** * Extracts a FacebookFriend object from a JSON object. The FacebookFriend * object has a superset of the fields that might be contained in the * node; only extracts those fields that are actually present. */ private FacebookFriend extractFriend(JSONObject obj) throws JSONException { FacebookFriend friend = new FacebookFriend(); friend.uid = obj.getString("uid"); for (Iterator it = obj.keys(); it.hasNext(); ) { String key = (String) it.next(); if ("name".equals(key)) { friend.name = obj.getString(key); } else if ("first_name".equals(key)) { friend.firstName = obj.getString(key); } } return friend; } }