
One of the challenges with writing a presumably successful Facebook application is taking care of scale. with an ever growing user base and the high viral growth potential brought by this social platform you could be looking at a very high traffic if your application is successful. It is wise to plan ahead. Integrating a service like Google App Engine or Amazon AWS could do the trick. Especially for small and medium enterprises which can find the cost model beneficial for their first baby steps.
This post is not going to dwell on the details of creating an App Engine account or a Facebook application. Those are described very well by their providers and across the web.
The example is an application called “famousity”. It authenticates a Facebook user then looks through his friends and determines how famous they are by executing a Google search on their exact name and comparing the hit count. Not very clever but will do in order to get a first feel of these tools.
After creating a Facebook application you should be see the following screen:

As you can see the Canvas URL is http://fbfamousity.appspot.com is where our Google App Engine application resides. We’re going to need our application id, API Key and App Secret values moving forward so we keep them handy by creating a class to encapsulate them (of course in a real world scenario we should have externalized these):
public class FacebookUtil {
private static final String API_KEY = "API_KEY"; // replace with real values from Facebook app configuration
private static final String SECRET = "SECRET"; // replace with real values from Facebook app configuration
private static final String APPLICATION_ID = "APPLICATION_ID "; // replace with real values from Facebook app configuration
private static final String FB_GRAPH_URL = "https://graph.facebook.com/";
private static final String FB_OAUTH_URL = FB_GRAPH_URL + "oauth/";
private static final String FB_FRIENDS_URL = FB_GRAPH_URL + "me/friends?";
// private static final String REDIRECT_URL =
// "http://apps.facebook.com/famousity/";
// localhost is for testing
private static final String REDIRECT_URL = "http://localhost:8888/";
public static String getApplicationId() {
return APPLICATION_ID;
}
public static String getAPIKey() {
return API_KEY;
}
public static String getSecret() {
return SECRET;
}
public static String getAuthorizeUrl() {
final StringBuilder sb = new StringBuilder(FB_OAUTH_URL);
sb.append("authorize?client_id=").append(APPLICATION_ID);
sb.append("&display=page&redirect_uri=").append(REDIRECT_URL);
sb.append("&scope=user_status,publish_stream,offline_access,email");
return sb.toString();
}
public static String getAccessTokenUrl(final String authCode) {
final StringBuilder sb = new StringBuilder(FB_OAUTH_URL);
sb.append("access_token?canvas=1&fbconnect=0&type=user_agent&client_id=").append(
APPLICATION_ID);
sb.append("&redirect_uri=").append(REDIRECT_URL);
sb.append("&client_secret=").append(SECRET);
sb.append("&code=").append(authCode);
return sb.toString();
}
public static String getFriendsUrl(final String authToken) {
return FB_FRIENDS_URL + authToken;
}
}
One thing to note here about this class is that the REDIRECT_URI field has a value of either http://localhost:8888/ or http://apps.facebook.com/famousity/ depending on weather we are working in our local development environment or the App Engine “production” environment. Remember to change this before deploying your application to App Engine (the change needs to take place in the Facebook application settings as well).
For my development environment I used STS with Google Integration. However, if you use Eclipse you can simply install the Google Eclipse Plugin which provides App Engine and GWT support within the IDE.
After installing the IDE plugin you get a new Google toolbar for creating a new web application, compiling GWT, profiling to speed tracer and deploying your app to App Engine. It seems that even tighter Eclipse integration is planned for the next version of the plugin.

Facebook’s authentication is composed of several steps:
The user initially goes to http://apps.facebook.com/famousity the canvas page is invoked. After that ourapplication needs to send an authorization request with the appropriate permissions. Something along the lines of:
https://graph.facebook.com/oauth/authorize?client_id=APP_CLIENT_ID&display=page&redirect_uri=http://localhost:8888/&scope=user_status,publish_stream,offline_access,email
Once the user authorizes our app it will redirect back to the parameter specified under “redirect_uri” with the access token.
This covers the initial authorization flow, but you must also account for the scenario where the user denies access to your app in which case face will provide you with an error message parameter in the form of:
http://YOUR_CANVAS_PAGE?error_reason=user_denied&error=access_denied&error_description=The+user+denied+your+request
The next time the user arrives at the application it has already been authorized but you still need to retrieve the access token. The application needs to execute access token request. It looks like:
https://graph.facebook.com/oauth/access_token?canvas=1&fbconnect=0&type=user_agent&client_id=APP_CLIENT_ID&redirect_uri=http://localhost:8888/&client_secret=APP_SECRET
After that the application can proceed to execute authorized graph API calls using the provided token:
https://graph.facebook.com/me/friends?access_token=FB_PROVIDED_ACCESS_TOKEN
To create a new GWT-App Engine-Facebook project open Eclipse and click the New Web Application Project, type the name and a package and click Finish. This will create a new GWT application. It will also generate some sample code, notice it has created a “client”, “server” and “shared” packages The client package should contain two interfaces the RemoteService specification interface and it’s Async correspondent. In our case we will create a Facebook service to handle facebook operations:
@RemoteServiceRelativePath("facebook")
public interface FacebookService extends RemoteService {
public String login(String authToken);
public List<FbFriend> findFriends(String authToken);
}
And it’s Async twin, an identical interface with another parameter, a typed AsyncCallback:
public interface FacebookServiceAsync {
public void login(String authToken, AsyncCallback<String> asyncCallback);
public void findFriends(String authToken, AsyncCallback<List<FbFriend>> asyncCallback);
}
Our Facebook service contains two methods, one is for the initial authentication of the user and accepts an existing authentication token used to pass back to the client. This lets the client know that the user was previously authenticated and can proceed into the app. For more information on the Facebook authentication flow check their documentation. The login method returns the authentication token which is later used in subsequent calls to the Facebook API.
The findFriends method accepts the authentication token and retrieves a list of FbFriend instances. Note that in GWT classes used to communicate between the client and the remote service must implement the IsSerializable interface.
public class FbFriend implements IsSerializable {
private Long id;
private String name;
public Long getId() {
return id;
}
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
public void setId(final Long id) {
this.id = id;
}
}
The FacebookService implementation is shown below
public class FacebookServiceImpl extends RemoteServiceServlet implements FacebookService {
private static final long serialVersionUID = 1L;
public String login(final String authToken) {
final String url = FacebookUtil.getAccessTokenUrl(Util.encode(authToken));
return Util.fetchURL(url);
}
public List<FbFriend> findFriends(final String authToken) {
final String friendsUrl = FacebookUtil.getFriendsUrl(encodeUrl(authToken));
final String json = Util.fetchURL(friendsUrl);
final FBFriends fbFriends = new Gson().fromJson(json, FBFriends.class);
return fbFriends.getData();
}
private static String encodeUrl(final String unencodedToken) {
final String[] parts = unencodedToken.split("=");
if (parts.length < 2) {
return "";
}
return "access_token=" + Util.encode(parts[1]);
}
}
Our FacebookService will handle the login and the friend retrieval but what about the Google name search hit counts? For this we devise another service with an async counterpart:
@RemoteServiceRelativePath("google")
public interface GoogleService extends RemoteService {
public Long findFriendRanking(FbFriend friend);
}
public interface GoogleServiceAsync {
public void findFriendRanking(FbFriend friend, final AsyncCallback<Long> asyncCallback);
}
And here is the implementation for this service:
public class GoogleServiceImpl extends RemoteServiceServlet implements GoogleService {
private static final long serialVersionUID = 1L;
private static final Logger logger = LoggerFactory.getLogger(Util.class);
private static final String GOOGLE_API_URL = "http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=";
private final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
public Long findFriendRanking(final FbFriend friend) {
final Key key = KeyFactory.createKey("profile", friend.getId());
try {
final Entity profile = datastore.get(key);
final Object result = profile.getProperty("estimatedResultCount");
return (Long) result;
} catch (final EntityNotFoundException e) {
logger.debug("Could not find an entry for {} in the datastore.", friend.getId());
final Long resultCount = findResultCount(friend.getName());
final Entity newProfile = new Entity(key);
newProfile.setProperty("profileName", friend.getName());
newProfile.setProperty("estimatedResultCount", resultCount);
datastore.put(newProfile);
return resultCount;
}
}
public Long findResultCount(final String name) {
final String queryUrl = GOOGLE_API_URL + Util.encode("\"" + name + "\"");
logger.debug("Executing google query {}", queryUrl);
final String resultJson = Util.fetchURL(queryUrl);
final ResponseDataContainer container = new Gson().fromJson(resultJson,
ResponseDataContainer.class);
if (null != container && null != container.getResponseData()
&& null != container.getResponseData().getCursor()) {
final Long resultCount = container.getResponseData().getCursor()
.getEstimatedResultCount();
return resultCount;
} else {
return -1L;
}
}
}
We create a key based on the friend’s Facebook id and then use that key to search the AppEngine datastore. If the key doesn’t exist we handle the EntityNotFoundException by executing a new search and placing the result values in the datastore for future use.
When working in the local development environment, notice that the AppEngine library has created a local datastore for you. This can be found under “war/WEB-INF/appengine-generated/local_db.bin” in our workspace.
In case you’re wondering about the validity of the results here it is a complete spoof. The Google Ajax Search API has been deprecated for quite some time now and the correctness of the results is dubious at best. It will do for this example but not for any real world apps.
Now to the GWT client code, here we need to perform a few basic steps:
We use the returned “code” parameter returned to us by Facebook to see if the user has an access token. If he doesn’t we redirect him to the authorization Url this will cause Facebook to display the following authorization dialog:

Next we check for the “user_denied” parameter place by the caller (Facebook) and display an appropriate error message to the user (if we want to force him to authorize all permissions, depending on what our app requires to function). If the user has denied our authorization request we better notify him that he needs to authorize us:

After we’re done with the authorization checks we can now safely proceed with our access token to retrieve the user’s friend list, using our FacebookService remote interface. For each friend returned we draw a widget then execute a name search using our GoogleService remote interface.
public class Famousity implements EntryPoint {
private final FacebookServiceAsync facebookService = GWT.create(FacebookService.class);
private final GoogleServiceAsync googleService = GWT.create(GoogleService.class);
private MessageBox messageBox;
public void onModuleLoad() {
final String authToken = Location.getParameter("code");
final String error = Location.getParameter("error_reason");
if (null != error && error.equals("user_denied")) {
userDenied();
} else if (authToken == null || "".equals(authToken)) {
redirect(FacebookUtil.getAuthorizeUrl());
} else {
messageBox = MessageBox.wait("Famousity", "", "Analyzing friend rankings...");
facebookService.login(authToken, new AsyncCallback<String>() {
public void onFailure(final Throwable caught) {
handleError(caught);
}
public void onSuccess(final String authToken) {
rankFriends(authToken);
}
});
}
}
private void userDenied() {
MessageBox.confirm("Error authrizing famousity",
"You have deined famousity from installing correctly, click 'Yes' to try again",
new Listener<MessageBoxEvent>() {
public void handleEvent(final MessageBoxEvent be) {
if (be.getButtonClicked().getText().equals("Yes")) {
redirect(FacebookUtil.getAuthorizeUrl());
} else {
be.getMessageBox().close();
}
}
});
}
private void rankFriends(final String authToken) {
final RootPanel rootPanel = RootPanel.get();
facebookService.findFriends(authToken, new AsyncCallback<List<FbFriend>>() {
public void onFailure(final Throwable caught) {
Window.alert(caught.getMessage());
}
public void onSuccess(final List<FbFriend> friends) {
closeMessageBox();
final Header header = new Header();
header.setText("How famous are your friends");
rootPanel.add(header);
for (final FbFriend friend : friends) {
final Panel friendPanel = new HorizontalPanel();
friendPanel.setStyleName("panel");
final Image profilePic = new Image(getProfilePictureUrl(friend));
profilePic.setStyleName("profilePic");
friendPanel.add(profilePic);
friendPanel.add(new Hidden(friend.getId().toString()));
friendPanel.add(new Text(friend.getName()));
final Text countText = new Text("");
friendPanel.add(countText);
rootPanel.add(friendPanel);
googleService.findFriendRanking(friend, new AsyncCallback<Long>() {
public void onFailure(final Throwable caught) {
handleError(caught);
}
public void onSuccess(final Long result) {
if (result > 0) {
countText.setText(result.toString());
} else {
countText.getParent().setVisible(false);
}
}
});
}
}
});
}
private void handleError(final Throwable caught) {
Window.alert(caught.getMessage());
}
private String getProfilePictureUrl(final FbFriend friend) {
return "http://graph.facebook.com/" + friend.getId() + "/picture";
}
private void closeMessageBox() {
if (messageBox != null) {
messageBox.close();
messageBox = null;
}
}
// redirect the browser to the given url
public static native void redirect(String url)/*-{
$wnd.location = url;
}-*/;
}
While the user is waiting a neat progress bar is displayed using the aid of GWT-EXT:

This is what the (censored) output looks like:

A few words about the GWT code here. GWT relies heavily on asynchronous calls. There is some suspicion that rises from nesting these calls although Google has a good explanation for why this is the way it is. Some discussion of this issue can be found here and here. It seems some recommend moving logic to the server while other try to devise more neat solutions for the code. In AppEngine more logic running on the server may pose a problem due to the 30 second limitation. We must take these matters under consideration when combining these two technologies. The need to explicitly implement the RemoteService and it’s Async twin seem a bit off as well, they smell a little like the old EJB stuff. Other MVC implementations save you this kind of boilerplate code by using annotations or configuration files.
After testing the application in Eclipse, click the “Deploy App Engine Project” button in Eclipse then provide the Google credentials and our application get’s compiled and deployed automatically. A pretty cool combination, for my next social project I think I am going to take a closer look at Spring Social.
Source code is available here.

Hi,
This is definitely a great post ! Its been really helpful especially for me, when I’m trying to learn about developing facebook app with gwt.
I’ve glanced at your source code. On Util.java, you have
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
where do you get these libraries from ? Really appreciate if you could reply Thanks !
| April 12, 2011 @ 9:46 AM
slf4j is a logging facade for java which abstracts away the underlying logging implementation (log4j, logback). The famousity project uses maven for artifact management, and the slf4j dependency is expressed in the maven pom.xml. You can see it here. Maven retrieves this depedency from a maven repository, these are configured in the pom.xml as well. For a quick intro to maven see this link. Hope this helps.
| April 12, 2011 @ 10:47 AM
Thanks erez !
What about com.extjs.gxt.ui.client ? Is that from Maven repository too ? I’m currently working with Eclipse 3.6 and its pretty obvious that I’m an amateur in this field.
I have found the eclipse plugin for Maven. Is that what I should be installing ? Or is there a work around solution without having to use Maven ?
I hope I didn’t confuse you
| April 12, 2011 @ 9:12 PM
Yes, extjs comes from a maven repository too. The eclipse maven plugin is certainly helpful. The maven download page has the instructions on how to install and use maven as well.
| April 16, 2011 @ 10:38 PM
Thanks for the great post Erez.
The only concern – by keeping FacebookUtil under shared, you are probably exposing the secret API keys.
| April 16, 2011 @ 6:41 AM
Hello,
great post. But I have one question. I try to test my app in development mode, so I use the localhost:
At the facebook app configuration site, I set the “Site URL” to “http://localhost:8888/” and the “Canvas URL” to “http://127.0.0.1:8888/MyFbApp.html?gwt.codesvr=127.0.0.1%3A9997″. But when I visit the “Canvas Page” (http://apps.facebook.com/my_fb_app), There pops up always a dialog box with the message: “Plugin failed to connect to development mode server at 127.0.0.1[..]“
| April 23, 2011 @ 5:44 AM
I’ve ran across the same problem, after reading this stackoverflow discussion I ended up removing everything after the port (e.g., use http://localhost:8888/ for both the “Site URL” under facebook settings AND the “returnUrl” query-string parameter I use for facebook requests. I think this means that you cannot debug GWT client code within eclipse (the debugger doesn’t halt on breakpoints), if you really need to debug the client-side code I suggest you use the original query string (with the gwt.codesvr parameter) but make sure you also use it for the “returnUrl” query string parameter and encode it correctly.
| April 23, 2011 @ 6:40 AM
Hey, thanks for the answer and for the stackoverflow link. The modification in the hosted.html works for me. But its also important to start a new debug session after the modification and as you described in your post to encode the redirection URL:
Client side:
com.google.gwt.http.client.URL.encodePathSegment(redirectionUrl)
Server side:
java.net.URLEncoder.encode(urlString, “UTF-8″)
I have still one question: Could it be that the app secret can be accessed from the client side? FacebookUtil.java is a shared class, so someone could call the getSecret() method from the client side with a hacked script or something else.
I get the app informations from the server by a RPC and the appSecret is a transient field.
| April 28, 2011 @ 4:29 AM
I didn’t understand, are you also able to debug your application from facebook?
setting the Canvas URL to http://127.0.0.1:8888/ is working
but setting it to: http://127.0.0.1:8888/hello.html?gwt.codesvr=127.0.0.1:9997/
pop up the message “Plugin failed to connect to development mode server at”
| August 10, 2011 @ 6:38 AM
Take a look at this link, solved the problem for me
August 10, 2011 @ 9:36 AM
This shows real expertise. Thanks for the ansewr.
December 12, 2011 @ 7:55 PM
how do i get the email addresses of friends list from my facebook account………. plz do reply.
| July 14, 2011 @ 11:10 PM
Take a look at the email field under the user’s profile, here is the documentation: http://developers.facebook.com/docs/reference/api/user/
| July 19, 2011 @ 12:22 AM
where to create FbFriend class?
| July 14, 2011 @ 11:23 PM
You don’t need to create it’s here: https://github.com/erezmazor/famousity/blob/master/famousity-webapp/src/org/echotech/famousity/shared/FbFriend.java. This class represents the basic information being drawn from the user’s profile in a java class.
| July 19, 2011 @ 12:24 AM
I tried to import the project into Eclipse via Import-Maven-Existing Projects.
But I didn’t figure out how to get it to work.
It always gets me the error:
package com.google.appengine.api.datastore does not exist
Does anybody know how to import it into eclipse?
Thx a lot
| July 25, 2011 @ 7:29 AM
You need to install Google plugin for eclipse, you can grab it from here. This will install Google App Engine. Alternatively you can do that manually see the provided link it also explains how to do that.
| July 25, 2011 @ 7:47 AM
How to create the famousity application in eclipse plz tell us in detail…..? and wat the html file contains? and how to get only the email addresses of all the friends?
| July 25, 2011 @ 10:48 PM
Ok. thx you a lot!
It worked quite well. I managed somehow to integrate it in my project. (with the same structure, Client, Server, Shared)
But after the login in FB via a new Window, there appears “Module needs to be (re-) compiled”.
Does anybody know, why this error could appear?
| July 27, 2011 @ 1:58 AM
I get an exception: {“error”:{“type”:”OAuthException”,”message”:”Error validating verification code.”}}
in the fetchURL method.
to resolve it we can change the type in the getAccessTokenUrl to type=”client_cred” but then we get an exception while trying to retrieve the friends list.
it’s seems to me like there is no work around then to use the session
and I’m not sure how to do it with an RPC call..
Can some one help?
| August 16, 2011 @ 12:02 PM
disregard this comment, I tried to redirect with http://localhost:8888/?gwt.codesvr=localhost:9997/ but it doesn’t work. changing it to http://localhost:8888/ work (but then I lost the ability to debug the client side.
Please help
| August 17, 2011 @ 4:07 AM
It is working, but I lost the ability to debug my client side as http://localhost:8888/?gwt.codesvr=localhost:9997/ will not work as a redirect_uri.
any suggestion?
| August 17, 2011 @ 3:46 AM
See my previous reply to the same issue, stackoverflow has a thread for this as well as this blog: http://notepad2.blogspot.com/2010/12/debug-google-web-toolkit-applications.html
| August 17, 2011 @ 7:04 AM
The link you provided explain how to debug in general, and this is something that I managed to do, but to work with facebook I can’t use the full url, I must omit the extension “?gwt.codesvr=localhost:9997/”
| August 17, 2011 @ 11:12 AM
No trailing forward-slash.
| August 17, 2011 @ 2:39 PM
What about Util.fetchURL(url)?¿¿ I don’t know what is the method and its library. Besides, every time I’m going to validate the code I receive
Error”: {
“message”: “Error validating verification code.”,
I just try to get an access_token. Thanks
| October 15, 2011 @ 1:53 PM
fetchUrl can be found here for any real purpose I suggest you use a decent HTTP library such as the apache one. For your error you should double check your verification code and look a the Facebook tutorial to verify the instructions above are not outdated
| October 15, 2011 @ 3:27 PM