Facebook Applications on Glassfish (part 1)

During this summer, I explored writing Facebook applications using Java EE, something I have wanted to look into for a while, but never got around to. Facebook had stopped official support for it's Java API, in May 2008, which is not so nice to the millions of Java programmers out there. Fortunately, the API has since evolved as Facebook Java API.  It is very usable and there are many blogs and examples on how to get started. After looking at various posts, it was relatively simple to write a basic facebook application and make it run on Glassfish application server. I will share what I have learned along the way.

I used a recent NetBeans Dev build (NetBeans IDE Dev (Build 200908070201))  and GlassFish v2.1, but feel free to use an setup you are comfortable with. The steps should work the same way with Eclipse or GlassFish v3.

Step 1

I am assuming you are a Facebook user. Who isn't these days :-). If not, go sign up first.

The next task is to get yourself facebook developer privileges, which you do by "installing" facebook developer application. The developer application allows you to register your new application, provide some basic details to facebook on where it runs, generate an Application Identifier, API key and Secret Key etc. which identify your application to facebook users and to facebook platform.

To get started, click on Setup New Application at the top of the page. 

Provide a name for your sample, Agree to the Facebook Terms and Save Changes.


After Step 1, facebook assigns an API key that identifies your Application's requests and also a secret key that must be supplied with every request This is what you will see after you hit Save Changes above.

I have whited out the App Id, API Key and Secret code that I obtained. You will see long hex strings. You have taken the first big step already.  There is an application now registered.

Step 2

Now provide some essential information about where your application is hosted, the main canvas page etc. If you are not familiar already, your facebook application will not run on facebook's servers. You have to host it somewhere. You can use a Glassfish or Tomcat hosting provider or do it from home, which is what I do. I use dyndns.org to get a public domain name that points back to my home server or laptop. This is obviously not recommended if your application becomes wildly popular, but it is good enough for this sample!

In Step 2, we will provide some more crucial information about your application.The bits of information that we plan to provide are under Canvas and Connect.


On this page, we will make some important choices.

  1. Canvas Page URL: Choose the common name that you want for your application's users. I chose glassbook. When facebook receives a request for this URL, it will map it to your application.
  2. Canvas Callback URL: Provide the full URL path to where your facebook application will eventually be running. I am hosting my sample on a domain called sailfin.webhop.net.  The domain is registered at dyndns.org, which offers free DNS services, with some limitations. Note the following:
    1. I used FacebookSample as the context root for my web application that will handle the application logic. You could choose anything you want for this. Just make sure to use the same context root when you develop the web application later.
    2. I declared that the receiver of facebook traffic is a servlet or JSP that is mapped to Canvas. You can use any name you want here and do the corresponding thing while developing the application.
  3. Use the defaults for all others. We will not use FBML in this sample.

 Now, click on Connect on the  left hand panel and supply the same path we provided for Canvas call back URL.


Thats it! You have registered an application. Now all that is left is to write it!

Step 3

Now we will develop the web application, called FacebookSample. In NetBeans, create a new project, called FacebookSample.

Note how I used the context root: FacebookSample


Then I created a servlet called Canvas:

And a ServletFilter called FacebokAuthFilter


 At the point, in NetBeans there should be two source files in the project structure.


You already know that we intend to put the application logic in Canvas.java servlet class.We have not filled in anything there yet. We will return to it soon.

Before we start writing code, need to add some Facebook Java API jar files to your web application. In NetBeans, you can do this by right clicking on the FacebookSample application, choosing Properties and then Libraries. You must add the following 3 jar files:

  1. commons-logging-1.1.1.jar
  2. facebook-java-api-2.1.1.jar
  3. json-20070829.jar

All of these are in the facebook Java API bundle you downloaded at the top of the tutorial.

Macintosh-202:lib Sreeram$ pwd
/Users/Sreeram/facebook-java-api-2.1.1/lib
dhcp-usca14-133-138:lib Sreeram$ ls -l 
total 3568
-rw-r--r--  1 Sreeram  Sreeram   62983 Dec 31  2007 activation-1.1.jar
-rw-r--r--  1 Sreeram  Sreeram  243016 Jan 15  2009 commons-lang-2.2.jar
-rw-r--r--  1 Sreeram  Sreeram   60686 Sep 20  2008 commons-logging-1.1.1.jar
-rw-r--r--  1 Sreeram  Sreeram  137560 May  1 08:26 facebook-java-api-2.1.1.jar
-rw-r--r--  1 Sreeram  Sreeram  278382 May  1 08:25 facebook-java-api-schema-2.1.1.jar
-rw-r--r--  1 Sreeram  Sreeram   89967 Sep 27  2008 jaxb-api-2.1.jar
-rw-r--r--  1 Sreeram  Sreeram  856752 Nov 24  2008 jaxb-impl-2.1.9.jar
-rw-r--r--  1 Sreeram  Sreeram   41829 Dec 31  2007 json-20070829.jar
-rw-r--r--  1 Sreeram  Sreeram   15949 Jan 15  2009 runtime-0.4.1.3.jar
-rw-r--r--  1 Sreeram  Sreeram   23346 Sep 27  2008 stax-api-1.0-2.jar

Now we are ready to start coding, but there is one other topic I need to introduce: why do we need FacebookAuthenticationFilter.java. That is the topic of the next section.

Step 4: Facebook Authentication

Only registered Facebook users can access your application. We need to authenticate users and force login if necessary. Login is handled by Facebook. Our application will make calls to Facebook APIs in the context of authenticated user.

Our application, may sometimes need permissions to do some things, such as read and publish to a stream. We need to request the user to grant such permissions.

We will use a Servlet Filter for check whether the user is logged in and request necessary permissions. 

Now lets dissect FacebookAuthenticationFilter.java

   /\*\*
     \* Init method for this filter
     \*/
    public void init(FilterConfig filterConfig) {
        this.filterConfig = filterConfig;
        if (this.filterConfig != null) {
            _apiKey = filterConfig.getInitParameter("api_key");
            _secretKey = filterConfig.getInitParameter("secret_key");
            if (debug) {
                log("FaceBookAuthFilter:Initializing filter");
            }
        }
    }

You need to supply the API Key and Secret Key received from facebook in the web.xml, so the Servlet Filter can use then in its requests redirected to facebook. This is what your web.xml would look like. Plugin the API key and Secret code you got from Facebook.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <filter>
        <filter-name>FacebookAuthFilter</filter-name>
        <filter-class>org.glassfish.samples.facebook.FacebookAuthFilter</filter-class>
        <init-param>
            <param-name>api_key</param-name>
            <param-value>Your API Key Here</param-value>
        </init-param>
        <init-param>
            <param-name>secret_key</param-name>
            <param-value>Your Secret Key Here</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>FacebookAuthFilter</filter-name>
        <url-pattern>/\*</url-pattern>
    </filter-mapping>
    <servlet>
        <servlet-name>Canvas</servlet-name>
        <servlet-class>org.glassfish.samples.facebook.Canvas</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>Canvas</servlet-name>
        <url-pattern>/Canvas</url-pattern>
    </servlet-mapping>
</web-app>

Back to the Filter

     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        try {
            FacebookJsonRestClient authClient = getAuthenticatedClient((HttpServletRequest) request,_apiKey, _secretKey);
            request.setAttribute("auth.client", authClient);
            filterConfig.getServletContext().setAttribute("fbc", request.getAttribute("auth.client"));
            chain.doFilter(request, response);
        } catch (FailedLoginException fle) {
            //user not logged in
            request.setAttribute("auth.client", null);
            forceLogin((HttpServletResponse) response);
        } catch (Exception e) {
            //handle exception
        }
    }

We first try to create a FacebookJsonRestClient object. This logic is encapsulated in the getAuthenticatedClient method. We will check the incoming request for the presence of two request parameters: auth_token and session_key. If a session key is present and is valid, the client object is instantiated. If only an auth_token is present, a client is instantiated and a new session created. The facebook session lasts about an hour. Infinite sessions are a different beast and one needs to request the user to grant offline access privileges. I have not played with it yet.

private FacebookJsonRestClient getAuthenticatedClient(HttpServletRequest request, String apiKey, String secretKey) throws FailedLoginException, FacebookException {
        String authToken = request.getParameter("auth_token");
        String sessionKey = request.getParameter(FacebookParam.SESSION_KEY.toString());
        FacebookJsonRestClient fbClient = null;
        if (sessionKey != null) {
            fbClient = new FacebookJsonRestClient(apiKey, secretKey, sessionKey);
        } else if (authToken != null) {
            fbClient = new FacebookJsonRestClient(apiKey, secretKey);
            //establish session
            fbClient.auth_getSession(authToken);
        } else {
            throw new FailedLoginException("Session key not found");
        }
        //fbClient.setIsDesktop(false);
        return fbClient;
    }

If there is no valid session established for the user, a FailedLoginException is thrown and we call forceLogin to cplete the Login process.  Otherwise, the client is objected is inserted into the request attributes for later retrieval.

     private void forceLogin(HttpServletResponse response) {
        try {
            String redirect = "http://www.facebook.com/login.php?" + "api_key=" + _apiKey + "&connect_display=popup" + "&v=1.0" + "&next=http://apps.facebook.com/glassbook" + "&cancel_url=http://www.facebook.com/connect/login_failure.html" + "&fbconnect=true" + "&return_session=true"
            response.sendRedirect(redirect);
        } catch (Exception ioe) {
            //handle exception
        }
    }

I used next=http://apps.facebook.com/glassbook to point to my test program. You will need to change the  next parameter to point to your application canvas URL.

 In the next part, I will walk through the rest of the application, the part that implements the canvas. Won't be long.

Comments:

Great Website... :) However I'm having some problem deploying.
Can I have the Source Code?

Thank You

Posted by guest on September 07, 2009 at 12:32 AM PDT #

Post a Comment:
Comments are closed for this entry.
About

Various things I do at Sun Microsystems.

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today