Here is complete code for making a facebook app in wicket. The code just lists all the user's friends.

Note: I'm not using the FaceBook client that comes from the FaceBook website. I'm using a version from this website: http://code.google.com/p/facebook-java-api/

This is the application class itself:

import com.facebook.api.FacebookRestClient;
import org.apache.wicket.*;
import org.apache.wicket.authorization.IUnauthorizedComponentInstantiationListener;
import org.apache.wicket.authorization.UnauthorizedInstantiationException;
import org.apache.wicket.authorization.strategies.page.AbstractPageAuthorizationStrategy;
import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.request.target.basic.RedirectRequestTarget;

import javax.security.auth.login.FailedLoginException;

public class FaceBookApp extends WebApplication implements IUnauthorizedComponentInstantiationListener {

    public static final String CLIENT = "auth.client";

    private String _apiKey = "put your own key here"; //replace this
    private String _secretKey = "put your own key here"; //replace this

    protected void init() {
        super.init();

        getSecuritySettings().setAuthorizationStrategy(new FaceBookAuthorizationStrategy());
        getSecuritySettings().setUnauthorizedComponentInstantiationListener(this);
    }

    public Class getHomePage() {
        return Login.class;
    }

    public void onUnauthorizedInstantiation(Component component) {
        if (component instanceof Page) {
            Page page = (Page) component;

            if (((FaceBookSession) page.getSession()).getClient() != null) {
                return;
            }

            FaceBookSession session = (FaceBookSession) page.getSession();
            try {
                FacebookRestClient authClient = FaceBookAuthHandler.getAuthenticatedClient(page.getRequest(), _apiKey, _secretKey);
                session.setClient(authClient);
            } catch (FailedLoginException fle) {
                //user not logged in
                forceLogin(page);

            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            throw new UnauthorizedInstantiationException(component.getClass());
        }
    }

    private void forceLogin(Page page) {

        page.getRequestCycle().setRequestTarget(new RedirectRequestTarget("http://www.facebook.com/login.php?api_key=" + _apiKey + "&v=1.0"));

    }

    public Session newSession(Request request, Response response) {
        return new FaceBookSession(request);
    }

    private static class FaceBookAuthorizationStrategy extends AbstractPageAuthorizationStrategy {
        protected boolean isPageAuthorized(final Class pageClass) {
            return false;
        }
    }
}

This is the FaceBookAuthHandler:

import com.facebook.api.FacebookParam;
import com.facebook.api.FacebookRestClient;
import org.apache.wicket.Request;

import javax.security.auth.login.FailedLoginException;

public class FaceBookAuthHandler {

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

}

This is the custom session object:

import com.facebook.api.FacebookRestClient;
import org.apache.wicket.Request;
import org.apache.wicket.protocol.http.WebSession;

public class FaceBookSession extends WebSession {

    private FacebookRestClient client;

    public FaceBookSession(Request request) {
        super(request);
    }

    public synchronized FacebookRestClient getClient() {
        return client;
    }

    public synchronized void setClient(FacebookRestClient client) {
        this.client = client;
    }
}

This is the wicket template:

<html>
<body>
  <div wicket:id="friends"><span wicket:id="friend">friend</span></div>
</body>
</html>

This is the Wicket page (the facebook callback URL):

import com.facebook.api.FacebookException;
import com.facebook.api.FacebookRestClient;
import com.facebook.api.schema.FriendsGetResponse;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;

import java.io.IOException;
import java.util.List;

public class Login extends WebPage {

    public Login() {
        try {
            FacebookRestClient client = ((FaceBookSession) getSession()).getClient();

            client.friends_get();

            FriendsGetResponse fbResponse = (FriendsGetResponse) client.getResponsePOJO();
            List<Long> friends = fbResponse.getUid();

            add(new ListView("friends", friends) {

                protected void populateItem(ListItem listItem) {
                    listItem.add(new Label("friend", listItem.getModelObjectAsString()));
                }
            });

        } catch (FacebookException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
Unregistered Application to Facebook User Problem

If your facebook profile is not associated with the application then client.friends_get() in the Login page will throw a NullPointerException.
This occurs because although the onUnauthorizedInstantiation method defined in the application class forces the login to occur in this case for some reason the Login page constructor is still called before the redirect takes place.

An ugly hack to make the demo work in this case is to add a test before client.friends_get() like:

    if (client == null) {
        WebMarkupContainer friends = new WebMarkupContainer("friends");
	friends.add(new Label("friend", "missing frields"));
    } else {
         client.friends_get();

         FriendsGetResponse fbResponse = (FriendsGetResponse) client.getResponsePOJO();
         List<Long> friends = fbResponse.getUid();

         add(new ListView("friends", friends) {

             protected void populateItem(ListItem listItem) {
                  listItem.add(new Label("friend", listItem.getModelObjectAsString()));
             }
         });

    }

Or, you can force Wicket to redirect to Facebook login page immediately - just change the forceLogin method:

private void forceLogin(Page page) {
    throw new RedirectToUrlException("http://www.facebook.com/login.php?api_key=" + _apiKey + "&v=1.0");
}
  • No labels