I've tried to follow the facebook-java-api filter example but i got this expection when i attempted to save to the client object to the session. The code is being hosted on the google appengine platform.
java.lang.RuntimeException: java.io.NotSerializableException: com.google.code.facebookapi.FacebookXmlRestClient
at com.google.apphosting.runtime.jetty.SessionManager.serialize(SessionManager.java:387)
at com.google.apphosting.runtime.jetty.SessionManager.createEntityForSession(SessionManager.java:364)
at com.google.apphosting.runtime.jetty.SessionManager$AppEngineSession.save(SessionManager.java:164)
at com.google.apphosting.runtime.jetty.SaveSessionFilter.doFilter(SaveSessionFilter.java:41)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
.....
at com.google.net.async.Connection.handleReadEvent(Connection.java:474)
at com.google.net.async.EventDispatcher.processNetworkEvents(EventDispatcher.java:831)
at com.google.net.async.EventDispatcher.internalLoop(EventDispatcher.java:207)
at com.google.net.async.EventDispatcher.loop(EventDispatcher.java:103)
at com.google.net.rpc.RpcService.runUntilServerShutdown(RpcService.java:251)
at com.google.apphosting.runtime.JavaRuntime$RpcRunnable.run(JavaRuntime.java:418)
at java.lang.Thread.run(Thread.java:636)
Caused by: java.io.NotSerializableException: com.google.code.facebookapi.FacebookXmlRestClient
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1173)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:343)
at java.util.HashMap.writeObject(HashMap.java:1018)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
I updated the filter code to use a map to save the session and associated client object but i still can get a valid login. Can anybody spot the issue with this code, or explain how the com.google.code.facebookapi.ExtensibleClient can be used correctly?
import com.google.code.facebookapi.FacebookException;
import com.google.code.facebookapi.FacebookWebappHelper;
import com.google.code.facebookapi.FacebookXmlRestClient;
import com.google.code.facebookapi.IFacebookRestClient;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import org.w3c.dom.Document;
public class FacebookFilter implements Filter {
private static final Logger logger = Logger.getLogger(FacebookFilter.class.getName());
private String api_key;
private String secret;
private static Map map = new HashMap();
public void init(FilterConfig filterConfig) throws ServletException {
api_key = filterConfig.getInitParameter("facebook_api_key");
secret = filterConfig.getInitParameter("facebook_secret_key");
if(api_key == null || secret == null) {
throw new ServletException("Cannot initialise Facebook User Filter because the " +
"facebook_api_key or facebook_secret context init " +
"params have not been set. Check that they're there " +
"in your servlet context descriptor.");
} else {
logger.info("Using facebook API key: " + api_key);
}
}
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
try {
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
HttpSession session = request.getSession(true);
IFacebookRestClient<Document> userClient = getUserClient(session);
if(userClient == null) {
logger.info("User session doesn't have a Facebook API client setup yet. Creating one and storing it in the user's session.");
userClient = new FacebookXmlRestClient(api_key, secret);
logger.info("add new session to map "+map.size()+" "+session.getId()+" "+userClient.toString());
map.put(session,userClient);
}
logger.fine("Creating a FacebookWebappHelper, which copies fb_ request param data into the userClient");
FacebookWebappHelper<Document> facebook = new FacebookWebappHelper<Document>(request, response, api_key, secret, userClient);
String nextPage = request.getRequestURI();
nextPage = nextPage.substring(nextPage.indexOf("/", 1) + 1); //cut out the first /, the context path and the 2nd /
logger.fine(nextPage);
boolean redirectOccurred = facebook.requireLogin(nextPage);
if(redirectOccurred) {
return;
}
redirectOccurred = facebook.requireFrame(nextPage);
if(redirectOccurred) {
return;
}
long facebookUserID;
try {
facebookUserID = userClient.users_getLoggedInUser();
logger.info("facebookUserID "+facebookUserID+" "+session.getId());
} catch(FacebookException ex) {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Error while fetching user's facebook ID");
logger.warning("Error while getting cached (supplied by request params) value " +
"of the user's facebook ID or while fetching it from the Facebook service " +
"if the cached value was not present for some reason. Cached value = {} "+ userClient.getCacheUserId());
return;
}
chain.doFilter(request, response);
}
}
public static FacebookXmlRestClient getUserClient(HttpSession session) {
if(map.containsKey(session))
{
logger.info("return match "+session.getId());
return (FacebookXmlRestClient) map.get(session);
}
else
{
logger.warning("getUserClient() null "+session.getId());
return null;
}
}
}