diff --git a/config/alfresco/web-scripts-application-context.xml b/config/alfresco/web-scripts-application-context.xml index ece3b74849..65293890e0 100644 --- a/config/alfresco/web-scripts-application-context.xml +++ b/config/alfresco/web-scripts-application-context.xml @@ -208,7 +208,9 @@ - + + + diff --git a/source/java/org/alfresco/web/scripts/FormData.java b/source/java/org/alfresco/web/scripts/FormData.java index 6e21c08e1e..9288bdeb6b 100644 --- a/source/java/org/alfresco/web/scripts/FormData.java +++ b/source/java/org/alfresco/web/scripts/FormData.java @@ -114,11 +114,21 @@ public class FormData implements Serializable, Scopeable return Context.getCurrentContext().newArray(this.scope, fields); } + /** + * Gets parameters encoded in the form data + * + * @return map (name, value) of parameters + */ /*package*/ Map getParameters() { return getParametersMap(); } + /** + * Gets files encoded in form data + * + * @return map (name, ScriptContent) of files + */ /*package*/ Map getFiles() { return getFilesMap(); @@ -127,7 +137,7 @@ public class FormData implements Serializable, Scopeable /** * Helper to parse servlet request form data * - * @return parsed form data + * @return map of all form fields */ private Map getFieldsMap() { @@ -155,6 +165,11 @@ public class FormData implements Serializable, Scopeable return fields; } + /** + * Helper to parse servlet request form data + * + * @return map of all form parameters + */ private Map getParametersMap() { if (parameters == null) @@ -173,6 +188,11 @@ public class FormData implements Serializable, Scopeable return parameters; } + /** + * Helper to parse servlet request form data + * + * @return map of all form files + */ private Map getFilesMap() { if (files == null) diff --git a/source/java/org/alfresco/web/scripts/bean/IndexUpdate.java b/source/java/org/alfresco/web/scripts/bean/IndexUpdate.java index 407edbf0c0..f64f1880be 100644 --- a/source/java/org/alfresco/web/scripts/bean/IndexUpdate.java +++ b/source/java/org/alfresco/web/scripts/bean/IndexUpdate.java @@ -32,6 +32,7 @@ import java.util.Map; import org.alfresco.web.scripts.DeclarativeWebScript; import org.alfresco.web.scripts.WebScriptRequest; import org.alfresco.web.scripts.WebScriptStatus; +import org.alfresco.web.scripts.facebook.FacebookService; /** @@ -41,7 +42,17 @@ import org.alfresco.web.scripts.WebScriptStatus; */ public class IndexUpdate extends DeclarativeWebScript { - + // component dependencies + private FacebookService facebookService; + + /** + * @param facebookService facebook service + */ + public void setFacebookService(FacebookService facebookService) + { + this.facebookService = facebookService; + } + /* (non-Javadoc) * @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) */ @@ -54,9 +65,19 @@ public class IndexUpdate extends DeclarativeWebScript String reset = req.getParameter("reset"); if (reset != null && reset.equals("on")) { + // reset list of web scripts int previousCount = getWebScriptRegistry().getWebScripts().size(); getWebScriptRegistry().reset(); tasks.add("Reset Web Scripts Registry; found " + getWebScriptRegistry().getWebScripts().size() + " Web Scripts. Previously, there were " + previousCount + "."); + + // reset facebook service + // TODO: Determine more appropriate place to put this + int appCount = facebookService.getAppModels().size(); + if (appCount > 0) + { + facebookService.reset(); + tasks.add("Reset " + appCount + " Facebook Applications."); + } } // create model for rendering diff --git a/source/java/org/alfresco/web/scripts/facebook/FacebookAPIRuntime.java b/source/java/org/alfresco/web/scripts/facebook/FacebookAPIRuntime.java index 2407a3167d..3c72975c93 100644 --- a/source/java/org/alfresco/web/scripts/facebook/FacebookAPIRuntime.java +++ b/source/java/org/alfresco/web/scripts/facebook/FacebookAPIRuntime.java @@ -37,7 +37,7 @@ import org.alfresco.web.scripts.WebScriptServletRuntime; /** - * HTTP Servlet Web Script Runtime + * Runtime to support requests from Facebook * * @author davidc */ diff --git a/source/java/org/alfresco/web/scripts/facebook/FacebookAPIServlet.java b/source/java/org/alfresco/web/scripts/facebook/FacebookAPIServlet.java index fc8b2064c5..5dc41a26f5 100644 --- a/source/java/org/alfresco/web/scripts/facebook/FacebookAPIServlet.java +++ b/source/java/org/alfresco/web/scripts/facebook/FacebookAPIServlet.java @@ -49,9 +49,7 @@ public class FacebookAPIServlet extends WebScriptServlet private static final Log logger = LogFactory.getLog(FacebookAPIServlet.class); - /* - * (non-Javadoc) - * + /* (non-Javadoc) * @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, * javax.servlet.http.HttpServletResponse) */ @@ -63,9 +61,9 @@ public class FacebookAPIServlet extends WebScriptServlet WebScriptRuntime runtime = new FacebookAPIRuntime(registry, serviceRegistry, authenticator, req, res, serverConfig); runtime.executeScript(); } - - /** - * @return default authenticator (bean name) + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptServlet#getDefaultAuthenticator() */ @Override protected String getDefaultAuthenticator() diff --git a/source/java/org/alfresco/web/scripts/facebook/FacebookAppModel.java b/source/java/org/alfresco/web/scripts/facebook/FacebookAppModel.java index c32c00083a..e1b9f41872 100644 --- a/source/java/org/alfresco/web/scripts/facebook/FacebookAppModel.java +++ b/source/java/org/alfresco/web/scripts/facebook/FacebookAppModel.java @@ -1,37 +1,86 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ package org.alfresco.web.scripts.facebook; + +/** + * Facebook Application + * + * @author davidc + */ public class FacebookAppModel { String appId; String apiKey; String secretKey; - + /** + * Construct + * + * @param apiKey + */ public FacebookAppModel(String apiKey) { this.apiKey = apiKey; } + /** + * @return application apiKey + */ public String getApiKey() { return apiKey; } + /** + * @return application secret + */ public String getSecret() { return secretKey; } + /** + * @param secretKey application secret + */ public void setSecret(String secretKey) { this.secretKey = secretKey; } + /** + * @return application id + */ public String getId() { return appId; } + /** + * @param appId application id + */ public void setId(String appId) { this.appId = appId; diff --git a/source/java/org/alfresco/web/scripts/facebook/FacebookAuthenticator.java b/source/java/org/alfresco/web/scripts/facebook/FacebookAuthenticator.java index e2a19c4020..0fd22c310b 100644 --- a/source/java/org/alfresco/web/scripts/facebook/FacebookAuthenticator.java +++ b/source/java/org/alfresco/web/scripts/facebook/FacebookAuthenticator.java @@ -36,6 +36,14 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +/** + * Web Script Authenticator that supports Facebook authentication + * mechanism. + * + * Upon success, the request is authenticated as the Facebook User Id. + * + * @author davidc + */ public class FacebookAuthenticator implements WebScriptServletAuthenticator { // Logger diff --git a/source/java/org/alfresco/web/scripts/facebook/FacebookError.java b/source/java/org/alfresco/web/scripts/facebook/FacebookError.java new file mode 100644 index 0000000000..c03404f436 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/facebook/FacebookError.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.web.scripts.facebook; + +/** + * Facebook Error. + * + * @author David Caruana + */ +public class FacebookError extends RuntimeException +{ + private static final long serialVersionUID = -7338963365877285084L; + + private int code = -1; + + public FacebookError(String msg) + { + super(msg); + } + + public FacebookError(int code, String msg) + { + super(msg); + this.code = code; + } + + public int getCode() + { + return code; + } + +} diff --git a/source/java/org/alfresco/web/scripts/facebook/FacebookModel.java b/source/java/org/alfresco/web/scripts/facebook/FacebookModel.java index 05fce4468c..e2152a4a0a 100644 --- a/source/java/org/alfresco/web/scripts/facebook/FacebookModel.java +++ b/source/java/org/alfresco/web/scripts/facebook/FacebookModel.java @@ -1,3 +1,27 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ package org.alfresco.web.scripts.facebook; import java.io.IOException; @@ -11,6 +35,11 @@ import com.facebook.api.FacebookException; import com.facebook.api.FacebookRestClient; +/** + * Facebook Javascript API + * + * @author davidc + */ public class FacebookModel { // Logger @@ -19,12 +48,22 @@ public class FacebookModel private FacebookServletRequest req; private FacebookRestClient client; private String[] friends; + private String[] appFriends; + + /** + * Construct + * + * @param req + */ public FacebookModel(FacebookServletRequest req) { this.req = req; } + /** + * @return the facebook rest client + */ private FacebookRestClient getClient() { if (client == null) @@ -40,10 +79,16 @@ public class FacebookModel { client = new FacebookRestClient(apiKey, secretKey, sessionKey); } + + if (logger.isDebugEnabled()) + client.setDebug(true); } return client; } - + + /** + * @return all friends of the logged in facebook user + */ public String[] getFriends() { if (friends == null) @@ -53,81 +98,152 @@ public class FacebookModel { try { - Document friendsDoc = getClient().friends_get(); - NodeList uids = friendsDoc.getElementsByTagName("uid"); - friends = new String[uids.getLength()]; + Document response = getClient().friends_get(); + NodeList uids = response.getElementsByTagName("uid"); + String[] uidsArray = new String[uids.getLength()]; for (int i = 0; i < uids.getLength(); i++) { - friends[i] = uids.item(i).getTextContent(); + uidsArray[i] = uids.item(i).getTextContent(); } + friends = uidsArray; } - catch(Exception e) + catch(FacebookException e) + { + throw new FacebookError(e.getCode(), e.getMessage()); + } + catch(IOException e) { - friends = new String[0]; + throw new FacebookError(e.getMessage()); } } } return friends; } - + + /** + * @return friends who are users of the current application + */ + public String[] getAppFriends() + { + if (appFriends == null) + { + try + { + Document response = getClient().friends_getAppUsers(); + NodeList uids = response.getElementsByTagName("uid"); + String[] uidsArray = new String[uids.getLength()]; + for (int i = 0; i < uids.getLength(); i++) + { + uidsArray[i] = uids.item(i).getTextContent(); + } + appFriends = uidsArray; + } + catch(FacebookException e) + { + throw new FacebookError(e.getCode(), e.getMessage()); + } + catch(IOException e) + { + throw new FacebookError(e.getMessage()); + } + } + return appFriends; + } + + /** + * Post User Action + * + * For details see: + * http://wiki.developers.facebook.com/index.php/Feed.publishActionOfUser + * + * @param title + * @param body + * @return + */ + public int postUserAction(String title, String body) + { + try + { + Document response = getClient().feed_publishActionOfUser(title, body); + int status = Integer.parseInt(response.getDocumentElement().getTextContent()); + return status; + } + catch (FacebookException e) + { + if (logger.isErrorEnabled()) + logger.error("Failed to post user action [title=" + title + ", body=" + body + "] due to " + e.toString()); + throw new FacebookError(e.getCode(), e.getMessage()); + } + catch (IOException e) + { + if (logger.isErrorEnabled()) + logger.error("Failed to post user action [title=" + title + ", body=" + body + "] due to " + e.toString()); + throw new FacebookError(e.getMessage()); + } + } + + /** + * @return user id of logged in facebook user + */ public String getUser() { return req.getUserId(); } + /** + * @return application id of current application + */ public String getAppId() { return req.getAppId(); } + /** + * @return session key of current facebook session + */ public String getSessionKey() { return req.getSessionKey(); } + /** + * @return application api key + */ public String getApiKey() { return req.getApiKey(); } - + + /** + * @return application secret key + */ + public String getSecret() + { + return req.getSecretKey(); + } + + /** + * @return facebook canvas path (as entered into 'Create Application' dialog) + */ public String getCanvasPath() { return req.getCanvasPath(); } + /** + * @return facebook canvas url (http://apps.facebook.com/canvasPath) + */ public String getCanvasURL() { return "http://apps.facebook.com/" + getCanvasPath(); } + /** + * @return facebook page url (http://apps.facebook.com/canvasPath/page) + */ public String getPageURL() { - return "http://apps.facebook.com" + req.getPathInfo(); + return "http://apps.facebook.com" + req.getPagePath(); } - public String getSecret() - { - return req.getSecretKey(); - } - - public boolean postUserAction(String title, String body) - { - try - { - Document result = getClient().feed_publishActionOfUser(title, body); - // TODO: check result - return true; - } - catch (FacebookException e) - { - if (logger.isDebugEnabled()) - logger.debug("Failed to post user action [title=" + title + ", body=" + body + "] due to " + e.toString()); - } - catch (IOException e) - { - if (logger.isDebugEnabled()) - logger.debug("Failed to post user action [title=" + title + ", body=" + body + "] due to " + e.toString()); - } - return false; - } } diff --git a/source/java/org/alfresco/web/scripts/facebook/FacebookService.java b/source/java/org/alfresco/web/scripts/facebook/FacebookService.java index a22ddd1d45..04adb8aaf7 100644 --- a/source/java/org/alfresco/web/scripts/facebook/FacebookService.java +++ b/source/java/org/alfresco/web/scripts/facebook/FacebookService.java @@ -1,3 +1,27 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ package org.alfresco.web.scripts.facebook; import java.util.HashMap; @@ -12,6 +36,11 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +/** + * Facebook Service + * + * @author davidc + */ public class FacebookService { // Logger @@ -21,17 +50,25 @@ public class FacebookService private Map apps = new HashMap(); private ReentrantReadWriteLock appsLock = new ReentrantReadWriteLock(); + // Component dependencies private WebScriptRegistry registry; private WebScriptContext context; - + + /** + * @param registry Web Script Registry + */ public void setRegistry(WebScriptRegistry registry) { this.registry = registry; } - - + /** + * Gets the application model for the given application api key + * + * @param apiKey api key + * @return application model + */ FacebookAppModel getAppModel(String apiKey) { FacebookAppModel facebookApp = null; @@ -98,11 +135,19 @@ public class FacebookService } } + /** + * Gets currently known Facebook Applications + * + * @return map (name, application) of known applications + */ public Map getAppModels() { return apps; } - + + /** + * Reset Facebook Service + */ public void reset() { appsLock.writeLock().lock(); @@ -115,4 +160,5 @@ public class FacebookService appsLock.writeLock().unlock(); } } + } diff --git a/source/java/org/alfresco/web/scripts/facebook/FacebookServlet.java b/source/java/org/alfresco/web/scripts/facebook/FacebookServlet.java index ce69ff7620..20bf71a2d8 100644 --- a/source/java/org/alfresco/web/scripts/facebook/FacebookServlet.java +++ b/source/java/org/alfresco/web/scripts/facebook/FacebookServlet.java @@ -50,9 +50,7 @@ public class FacebookServlet extends FacebookAPIServlet protected FacebookService facebookService; - /* - * (non-Javadoc) - * + /* (non-Javadoc) * @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, * javax.servlet.http.HttpServletResponse) */ @@ -64,7 +62,10 @@ public class FacebookServlet extends FacebookAPIServlet WebScriptRuntime runtime = new FacebookServletRuntime(registry, serviceRegistry, authenticator, req, res, serverConfig, facebookService); runtime.executeScript(); } - + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptServlet#initServlet(org.springframework.context.ApplicationContext) + */ @Override protected void initServlet(ApplicationContext context) { diff --git a/source/java/org/alfresco/web/scripts/facebook/FacebookServletRequest.java b/source/java/org/alfresco/web/scripts/facebook/FacebookServletRequest.java index d92c7f9a84..afce511a14 100644 --- a/source/java/org/alfresco/web/scripts/facebook/FacebookServletRequest.java +++ b/source/java/org/alfresco/web/scripts/facebook/FacebookServletRequest.java @@ -33,7 +33,7 @@ import org.alfresco.web.scripts.WebScriptServletRequest; /** - * HTTP Servlet Web Script Request + * Facebook Servlet Request * * @author davidc */ @@ -57,47 +57,74 @@ public class FacebookServletRequest extends WebScriptServletRequest this.pathInfo = pathInfo; } + /** + * @param secretKey application secret + */ /*package*/ void setSecretKey(String secretKey) { this.secretKey = secretKey; } + /** + * @param appId application id + */ /*package*/ void setAppId(String appId) { this.appId = appId; } + /** + * @return application api key + */ public String getApiKey() { return getParameter("fb_sig_api_key"); } + /** + * @return Facebook user id + */ public String getUserId() { return getParameter("fb_sig_user"); } - + + /** + * @return session key + */ public String getSessionKey() { return getParameter("fb_sig_session_key"); } + /** + * @return true => within Facebook canvas + */ public boolean isInCanvas() { String canvas = getParameter("fb_sig_api_key"); return (canvas == null || canvas.equals("1")); } + /** + * @return application secret + */ public String getSecretKey() { return secretKey; } + /** + * @return application id + */ public String getAppId() { return appId; } - + + /** + * @return application canvas path + */ public String getCanvasPath() { String pathInfo = getPathInfo(); @@ -109,6 +136,22 @@ public class FacebookServletRequest extends WebScriptServletRequest return pathSegments[2]; } + /** + * @return application page path + */ + public String getPagePath() + { + String pagePath = getPathInfo(); + if (pagePath.startsWith("/facebook")) + { + pagePath = pathInfo.substring("/facebook".length()); + } + return pagePath; + } + + /** + * @return friends of authenticated Facebook user + */ public String[] getFriends() { String[] friends; @@ -117,9 +160,13 @@ public class FacebookServletRequest extends WebScriptServletRequest return friends; } + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptServletRequest#getPathInfo() + */ @Override public String getPathInfo() { return pathInfo; } + } diff --git a/source/java/org/alfresco/web/scripts/facebook/FacebookServletRuntime.java b/source/java/org/alfresco/web/scripts/facebook/FacebookServletRuntime.java index 21cd785060..a7a8965a16 100644 --- a/source/java/org/alfresco/web/scripts/facebook/FacebookServletRuntime.java +++ b/source/java/org/alfresco/web/scripts/facebook/FacebookServletRuntime.java @@ -38,7 +38,7 @@ import org.apache.commons.logging.LogFactory; /** - * HTTP Servlet Web Script Runtime + * Facebook Canvas Page Servlet. * * @author davidc */ @@ -47,6 +47,7 @@ public class FacebookServletRuntime extends FacebookAPIRuntime // Logger private static final Log logger = LogFactory.getLog(FacebookServletRuntime.class); + // Component dependencies protected FacebookService facebookService; /** @@ -86,18 +87,27 @@ public class FacebookServletRuntime extends FacebookAPIRuntime return fbreq; } + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptServletRuntime#getScriptUrl() + */ @Override protected String getScriptUrl() { return "/facebook" + super.getScriptUrl(); } + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRuntime#getStatusCodeTemplate(int) + */ @Override protected String getStatusCodeTemplate(int statusCode) { return "/fbml." + statusCode + ".ftl"; } + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRuntime#getStatusTemplate() + */ @Override protected String getStatusTemplate() {