Java Facebook applications on Google App Engine

Create, implement, and deploy a Facebook application on Google App Engine

Launched in February 2004, Facebook is the world's largest social network, with more than 900 million users using the site to share content with their connected friends. Facebook Platform, launched in May 2007, enables third parties to write applications that integrate with Facebook. The platform initially supported a wide variety of programming languages — including Java — but now it provides native SDKs only for JavaScript and PHP (as well as support for applications on iOS and Android devices). However, the open source RestFB project has been maintaining the Java API since Facebook discontinued it (see Related topics).

Google App Engine (GAE) is a Platform as a Service (PaaS) that enables registered developers to run applications that they write in Python, Java, or Go on Google's infrastructure. This article shows you how to register a Facebook application, develop it in Java, and deploy it for free on GAE for use by any logged-in Facebook user. (Note that Google imposes a daily limit on the resources that each application deployed on GAE can use.)

The simple application you will create lists all of the user's friends with their IDs and profile pictures — similar to the previous look and feel of the friends page on a Facebook user's profile. To develop the application, you need:

A Facebook account

A Google account

The Eclipse IDE with the GAE plug-in installed (see Related topics)

Familiarity with using Eclipse

Sample code for the application is also available for download.

Registering the application

The first step is to register your application on both Facebook and GAE. It's a good practice to create the application on both platforms at the same time to ensure that the information you enter matches up as needed.

Register a Facebook application

Log into Facebook and launch the developer application at https://developers.Facebook.com/apps. (If you're launching it for the first time, you must grant the application access to your profile in order to continue.)

Click Create New App in the top right of the Apps page to display the Create New App dialog, shown in Figure 1:

Figure 1. Facebook Create New App dialog box

Enter a valid name and an available namespace for the application. The namespace is a single-word unique identifier to be used in a Facebook app URL. (In Figure 1, I've entered My Old Friends as the app name and myoldfriends as the namespace.) Leave the option for free hosting provided by Heroku unselected and click Continue. Type the CAPTCHA code in the next dialog and click Submit to bring up the basic settings dialog for your new application, shown in Figure 2:

Figure 2. Facebook application basic settings dialog

Note the App ID and App Secret keys at the top of the screen (hidden in Figure 2). Facebook uses them to identify your application. Keep them private and do not allow other developers to use them, because they could be used maliciously without your knowledge.

Enter an application domain in the App Domains field. This must be the GAE domain that you'll register for the application on the GAE developer site, so it must end with .appspot.com . For example, in Figure 2, I entered myoldfacebookfriends.appspot.com . Because this domain is no longer available, you'll have to use a different one. Just make sure it matches the application identifier that you use when you register the GAE app.

Under Select how your app integrates with Facebook, select Website with Facebook Login and enter a site URL consisting of the GAE domain you entered in the App Domains field, preceded by http:// . (In Figure 2, I've entered http://myoldfacebookfriends.appspot.com .)

The canvas URL The canvas URL you specify in the basic settings for your app tells Facebook where to get the page code to populate the Canvas Page — a blank canvas within Facebook where your application runs. When a user requests the Canvas Page, Facebook loads the Canvas URL within an <iframe> on that page.

Select App on Facebook and enter the canvas URL for a servlet in which the application will run. For this application, the canvas URL ends with a question mark to indicate that the parameters for the application will be passed in via the request URL sent to the application. The secure canvas URL is the same as the canvas URL, except that https replaces http . Again, the question mark at the end of the URL is important. (The URL for my app's servlet is http://myoldfacebookfriends.appspot.com/myoldfacebookfriends, so in Figure 2, I've entered http://myoldfacebookfriends.appspot.com/myoldfacebookfriends? for the canvas URL and https://myoldfacebookfriends.appspot.com/myoldfacebookfriends? for the secure canvas URL.)

This is all you need to do to set up an application on Facebook, but it's a good idea to configure some of the other settings, such as the app's icon and its category, to modify how the application is presented to users.

Register the application with GAE

With the application now registered with Facebook, you'll next register it with GAE.

Sign in on the applications page on GAE — https://appengine.google.com/ — and click Create Application. Under Application Identifier, enter the same app domain name that you used in the Facebook application basic settings. (The appspot.com portion is provided for you.) You can use whatever you want for the application title, which is used in searches for registered applications. Leave the remaining options with their defaults.

Figure 3. The Create an Application dialog for GAE

Click Create Application to finish the GAE registration process.

Developing the application

In Eclipse, create a new GAE project by clicking File > New > Web Application Project, or the New Web Application Project button under the Google Services and Deployment Tools menu. Enter a project name and a package name. Deselect Use Google Web Toolkit. Download the RestFB JAR file (see Related topics) and add it to the project's WEB-INF/lib folder.

Add the servlet definition for the application to the project's web.xml file. Listing 1 shows the definition I used:

Listing 1. Servlet definition

<?xml version="1.0" encoding="utf-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <servlet> <servlet-name>myoldFacebookfriendsServlet</servlet-name> <servlet-class>com.Facebook.friends.MyOldFacebookFriendsServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>myoldFacebookfriendsServlet</servlet-name> <url-pattern>/myoldFacebookfriends</url-pattern> </servlet-mapping> </web-app>

Note that the <url-pattern> is the same as in the canvas URL in the Facebook application basic settings dialog, but without the question mark.

Since October 2011, Facebook applications have required Secure Sockets Layer (SSL) to be enabled; it is disabled by default on GAE. To enable it, add the following line to appengine-web.xml:

<ssl-enabled>true</ssl-enabled>

The Facebook signed request

Using the HTTP POST method, Facebook sends a signed request to the application servlet to create the application's content. This request contains a 64-bit encoded payload containing, among other metadata, the OAuth token for the application for the current user. This is included in the payload of the request only if the user has granted the application access to his or her profile. You need to convert it to a Java object so that the application can use it.

Listing 2 shows the source for the Java object of the signed request. I've omitted all appropriate get and set methods for clarity; they're included in the source-code download (see Download).

Listing 2. The signed-request object

import org.apache.commons.codec.binary.Base64; import org.codehaus.jackson.map.ObjectMapper; public class FacebookSignedRequest { private String algorithm; private Long expires; private Long issued_at; private String oauth_token; private Long user_id; private FacebookSignedRequestUser user; public static class FacebookSignedRequestUser { private String country; private String locale; private FacebookSignedRequestUserAge age; public static class FacebookSignedRequestUserAge { private int min; private int max; } } }

You can decode the payload with Base64 in the Apache Commons Codec library. The decoded payload is in JavaScript Object Notation (JSON) and can be converted to a Java object using the Jackson JSON processor. Download their JAR files and add them to the project (see Related topics). Add the static helper method shown in Listing 3 to the FacebookSignedRequest class to create the object:

Listing 3. Helper method for encoding and decoding the payload

public static FacebookSignedRequest getSignedRequest(String signedRequest) throws Exception { String payload = signedRequest.split("[.]", 2)[1]; payload = payload.replace("-", "+").replace("_", "/").trim(); String jsonString = new String(Base64.decodeBase64(payload.getBytes())); return new ObjectMapper().readValue(jsonString, FacebookSignedRequest.class); }

Create the servlet

Now you can start coding the application that will run in a servlet. Create a new class with the same signature as the <servlet-class> definition in web.xml. First, you need to extract the OAuth token from the payload, using the SignedRequest class, as shown in Listing 4:

Listing 4. Extracting the OAuth token

String signedRequest = (String) request.getParameter("signed_request"); FacebookSignedRequest FacebookSR = null; try { FacebookSR = FacebookSignedRequest.getSignedRequest(signedRequest); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } String oauthToken = FacebookSR.getOauth_token();

If the oauthToken object is null, then the user has not granted access to the application and must be redirected to the authentication URL. The URL, which is standard across all applications, is in the following format:

https://www.Facebook.com/dialog/oauth?client_id=API KEY&redirect_uri= https://apps.Facebook.com/Application Namespace/&scope=Permissions

API KEY and Application Namespace in the authentication URL are the ones displayed in the Facebook basic settings dialog for the application. Permissions is the list of permissions needed for your application. All applications have basic permissions by default, and you needn't add any others for this article's purposes. (See Related topics for a link to the complete list of available permission.)

You can customize the look and feel of this page in the Settings > Auth Dialog page of the Facebook developer application. Ordinarily, you would use the servlet HttpServletRequest.sendRedirect() method, but because the application will be running in an <iframe> on the apps.Facebook.com domain, a short JavaScript snippet, shown in Listing 5, changes the location of the browser window to the application URL:

Listing 5. JavaScript code redicting to the application URL

PrintWriter writer = response.getWriter(); if(oauthToken == null) { response.setContentType("text/html"); String authURL = "https://www.Facebook.com/dialog/oauth?client_id=" + API_KEY + "&redirect_uri=https://apps.Facebook.com/myoldfriends/&scope="; writer.print("<script> top.location.href='" + authURL + "'</script>"); writer.close(); }

The Facebook Graph API The Graph API enables you to read the Facebook social graph's properties and connections. You can read specific fields, get pictures of any object, introspect an object for metadata, and get real-time updates on changes.

With a valid OAuth token, you can create a DefaultFacebookClient from the RestFB library and use it to retrieve data from Facebook's Graph API using the fetchConnection() call. Go to the Graph Explorer on Facebook at https://developers.Facebook.com/tools/explorer. Select the application you are developing from the drop-down box in the top right and click Get access token to grant access. Click on the various links under the Connections heading to see the results.

To get the user's friends, click the friends link and view the results. Note that the value of the URL in the explorer is user id/friends . The connection parameter in the function call would normally use the same value as in the Graph Explorer. But because the application uses the data of the logged-in user, you can replace the user ID with me , making the value me/friends . The call returns the raw Connection type, and because the class type is User , you need to add it as a parameter. The final call is:

Connection<User> myFriends = FacebookClient.fetchConnection("me/friends", User.class);

The result of the fetchConnection() method call is held in a List of List objects in the Connection class. The Connection class implements the Iterable interface, so you can obtain each List object in the List by using the enhanced for loop:

for (List<User> myFriendsList : myFriends)

On each iteration of the loop, the myFriendsList object contains the current list of users for that returned data page. Each User object in this list is used to create a line in the table of users the servlet will create. Although the user ID and name can be retrieved from the User object, the profile picture cannot. However, Facebook provides a URL for retrieving the profile picture of any user: https://graph.facebook.com/User ID/picture. Thus, the URL of the profile picture is created by replacing User ID in the URL with the user ID from the User object. Using the same PrintWriter object as before, write a table with a header row to the canvas:

writer.print("<table><tr><th>Photo</th><th>Name</th><th>Id</th></tr>");

Iterate through the list of User objects, as just described, then write a new row for this table, using the instance variables from each User object:

for (List<User> myFriendsList : myFriends) { for(User user: myFriendsList) writer.print("<tr><td>" + "<img src=\"https://graph.facebook.com/" + user.getId() + "/picture\"/>" + "</td><td>" + user.getName() +"</td><td>" + user.getId() + "</td></tr>"); }

Finally, close the <table> tag, and close the PrintWriter object to complete the servlet:

writer.print("</table>"); writer.close();

Listing 7 shows the final servlet doPost() method:

Listing 7. The doPost() method

public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String signedRequest = (String) request.getParameter("signed_request"); FacebookSignedRequest facebookSR = null; try { facebookSR = FacebookSignedRequest.getSignedRequest(signedRequest); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } String oauthToken = facebookSR.getOauth_token(); PrintWriter writer = response.getWriter(); if(oauthToken == null) { response.setContentType("text/html"); String authURL = "https://www.facebook.com/dialog/oauth?client_id=" + Constants.API_KEY + "&redirect_uri=https://apps.facebook.com/myoldfriends/&scope="; writer.print("<script> top.location.href='" + authURL + "'</script>"); writer.close(); } else { FacebookClient facebookClient = new DefaultFacebookClient(oauthToken); Connection<User> myFriends = facebookClient.fetchConnection("me/friends", User.class); writer.print("<table><tr><th>Photo</th><th>Name</th><th>Id</th></tr>"); for (List<User> myFriendsList : myFriends) { for(User user: myFriendsList) writer.print("<tr><td><img src=\"https://graph.facebook.com/" + user.getId() + "/picture\"/></td><td>" + user.getName() + "</td><td>" + user.getId() + "</td></tr>"); } writer.print("</table>"); writer.close(); } }

Deploying the application

With the servlet created, the application is ready to be deployed. Click the Google icon in Eclipse and select Deploy to App Engine. After the application is compiled and uploaded to the server, you (and any other Facebook user) can install the application in Facebook at http://apps.facebook.com/APP ID/ and see the results.

Conclusion

This article has demonstrated how to register, implement, and deploy a Facebook application in Java, hosted on the Google App Engine service. Now that you're familiar with the basics, I suggest you experiment with some variations.

Instead of writing the HTML for the content directly to the page, you could implement a more traditional Model-View-Controller (MVC) approach by using the standard RequestDispatcher.forward() call to a JavaServer Pages (JSP) page.

You could try creating an application that uses some of the extra permissions to data supplied by the Graph API. You pass the list of permissions an application needs to the authentication URL by adding each one to the scope request parameter. RestFB provides a helper method — StringUtils.join() — to create the list correctly. It takes a single String array as a parameter; each entry in the array is a permission name.

Finally, you could try to recreate the sample application using the Facebook-java-api Google Code project — an alternative implementation of the Facebook API — instead of RestFB (see Related topics).

Downloadable resources

Related topics