I had a really hard time implementing Facebook with Wicket, and mostly that was because the examples were out dated. This example is for using Facebook connect with wicket and the facebook-java-api found here: http://code.google.com/p/facebook-java-api/ The docs were not much help, so I feel obligated to put what I did to get things working.
For starters, I added the dependency to maven:
Code Block |
---|
title | pom.xml |
---|
borderStyle | solid |
---|
|
<dependency>
<groupId>com.google.code.facebookapi</groupId>
<artifactId>facebook-java-api-schema</artifactId>
<version>2.1.1</version>
</dependency>
|
We use a Panel to display login information.
Code Block |
---|
title | SimplePanel.html |
---|
borderStyle | solid |
---|
|
<html xmlns:wicket>
<body>
<wicket:panel>
<!-- facebook api as of 8/11/09 -->
<script src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php" type="text/javascript"></script>
<!-- function for facebook to execute on login-->
<script type="text/javascript" wicket:id="fbcallback">
function callWicket() {
var wcall = wicketAjaxGet('$url$' + '$args$', function() { }, function() { });
}
</script>
<div id="loginform">
<div wicket:id="fbloginDiv" style="display:none;">
<span wicket:id="fblogin">
<!-- facebool login button -->
<fb:login-button onlogin='callWicket();'></fb:login-button>
</span>
<!-- facebook api -->
<script type="text/javascript">
FB.init("your-api-key", "/xd_receiver.htm");
</script>
</div>
</div>
</wicket:panel>
</body>
</html>
|
The panel caused me a slight issue when setting up the AbstractDefaultAjaxBehavior. I found that I had to add my Panel to my Page before I could get the callbackUrl from the behavior. Once I did that, everything was ok. Here is a simple panel example that illustrates one way to add the <fb:login to your page and handle a callback from Facebook.
Code Block |
---|
title | SimplePanel.java |
---|
borderStyle | solid |
---|
|
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.wicket.Page;
import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.behavior.SimpleAttributeModifier;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.protocol.http.WebResponse;
import org.apache.wicket.protocol.http.servlet.ServletWebRequest;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.GrantedAuthorityImpl;
import org.springframework.security.context.SecurityContext;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.security.context.SecurityContextImpl;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import com.google.code.facebookapi.FacebookException;
import com.google.code.facebookapi.FacebookJsonRestClient;
import com.google.code.facebookapi.FacebookWebappHelper;
import com.google.code.facebookapi.ProfileField;
import com.pigspigot.model.User;
/**
* An example Panel that shows one way to output a facebook login button using fbml
* and getting a callback from Facebook.
*
* @author russellsimpkins@hotmail.com
*
*/
public class SimplePanel extends Panel {
private static final Log log = LogFactory.getLog(SimplePanel.class);
private WebMarkupContainer fbloginDiv;
private Label fblogin;
public SimplePanel(String id) {
super(id);
// TODO Auto-generated constructor stub
}
/**
* This method will the panel
*/
public void createPanel() {
fbloginDiv = new WebMarkupContainer("fbloginDiv");
fbloginDiv.setOutputMarkupId(true).setMarkupId("fbloginDiv");
fblogin = new Label("fblogin", "<fb:login-button onlogin='callWicket();'></fb:login-button>");
fblogin.setEscapeModelStrings(false);
fblogin.setOutputMarkupId(true);
if (isAuthenticated()) {
fbloginDiv.add(new SimpleAttributeModifier("style", "display:none;"));
}
fbloginDiv.add(fblogin);
addOrReplace(fbloginDiv);
/**
* This will only be called after they're logged in via facebook
*/
final AbstractDefaultAjaxBehavior behave = new AbstractDefaultAjaxBehavior() {
protected void respond(final AjaxRequestTarget target) {
// deal with facebook
handleFacebookCallback(target.getPage());
fbloginDiv.add(new SimpleAttributeModifier("style", "display:none;"));
target.addComponent(fbloginDiv);
}
};
add(behave);
CharSequence url = behave.getCallbackUrl();
StringBuffer sb = new StringBuffer();
sb.append("function callWicket() { \n");
sb.append(" var wcall = wicketAjaxGet('");
sb.append(url);
sb.append("', function() { }, function() { });");
sb.append(" }");
Label fbcallback = new Label("fbcallback", sb.toString());
fbcallback.setOutputMarkupId(true);
fbcallback.setEscapeModelStrings(false);
add(fbcallback);
}
/**
* All that we do to log you in from facebook. I put my fbook.key and fbook.secret in the
* properties file.
* @param thePage
*/
public void handleFacebookCallback(Page thePage) {
HttpServletRequest req = ((ServletWebRequest) thePage.getRequest()).getHttpServletRequest();
HttpServletResponse res = ((WebResponse) thePage.getResponse()).getHttpServletResponse();
String api = getLocalizer().getString("fbook.key", this);
String secret = getLocalizer().getString("fbook.secret", this);
FacebookWebappHelper<Object> helper = FacebookWebappHelper.newInstanceJson(req, res, api, secret);
// make sure the login worked
if (helper.isLogin()) {
FacebookJsonRestClient facebookClient = (FacebookJsonRestClient) helper.getFacebookRestClient();
long id;
try {
// grab the logged in user's id
id = facebookClient.users_getLoggedInUser();
// you can bundle ajax calls...
facebookClient.beginBatch();
// i'm going to call the users.getInfo fb api call, just to make sure it works
ArrayList<Long> ids = new ArrayList<Long>();
ids.add(new Long(id));
// put together a set of fields for fb to return
HashSet<ProfileField> fields = new HashSet<ProfileField>();
fields.add(ProfileField.FIRST_NAME);
fields.add(ProfileField.LAST_NAME);
// get the user data
facebookClient.users_getInfo(ids, fields);
// execute the batch (which also terminates batch mode until beginBatch is called again)
List<? extends Object> batchResponse = facebookClient.executeBatch(false);
JSONArray userInfo = (JSONArray) batchResponse.get(0);
JSONObject user = userInfo.getJSONObject(0);
// a pojo user object
User theUser = new User();
String username = user.getString("first_name");
theUser.setUsername(username);
// fb emails are proxy, my app needs some kind of holder
theUser.setEmail("noreply@facebook.com");
theUser.setUserId(new Integer(0));
theUser.setFacebook(true);
theUser.setFacebookId(id);
// we use spring, so here we give basic access to the facebook user.
List<GrantedAuthority> gaList = new ArrayList<GrantedAuthority>();
gaList.add(new GrantedAuthorityImpl("STANDARD"));
theUser.setAuthorities(gaList.toArray(new GrantedAuthority[] {}));
GrantedAuthority[] ga = theUser.getAuthorities();
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(theUser, theUser, ga);
SecurityContext context = new SecurityContextImpl();
context.setAuthentication(authentication);
SecurityContextHolder.setContext(context);
} catch (FacebookException e) {
log.error("facebook issues: " + e);
} catch (JSONException e) {
log.error("facebook json issues: " + e);
}
}
}
/**
* Do your own kind of auth check
* @return
*/
public boolean isAuthenticated() {
return SecurityContextHolder.getContext().getAuthentication() != null;
}
}
|
The Panel is added to your Page like so:
Code Block |
---|
title | SimplePage.java |
---|
borderStyle | solid |
---|
|
SimplePanel myPanel = new SimplePanel("your-wicket-id");
// make sure you add the panel first
add(myPanel);
// now you can create the panel contents
myPanel.createPanel();
|