From 4ed645e960006b7542c35eabb5c8058732b1237d Mon Sep 17 00:00:00 2001 From: David Caruana Date: Tue, 30 Oct 2007 18:06:00 +0000 Subject: [PATCH] First cut of Facebook integration: 1) Web Script framework extensions for supporting the development of Alfresco based Facebook applications 2) Sample Document Library Facebook application 3) FormData enhancements for supporting request args retrieval for multipart/form-data encoding 4) Sort order added to Search Javascript API Note: Stuff needs commenting, tidy up, but at least it's in SVN. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@7259 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../templates/webscripts/fbml.status.ftl | 46 +++ .../org/alfresco/scriptdump.get.html.ftl | 2 +- .../web-scripts-application-context.xml | 12 + .../web/app/servlet/PageRendererServlet.java | 4 +- .../web/scripts/AbstractWebScript.java | 32 +- .../web/scripts/BasicHttpAuthenticator.java | 4 +- .../org/alfresco/web/scripts/FormData.java | 293 ++++++++++-------- .../web/scripts/WebClientAuthenticator.java | 4 +- .../web/scripts/WebScriptRuntime.java | 29 +- .../web/scripts/WebScriptServlet.java | 22 +- .../WebScriptServletAuthenticator.java | 6 +- .../web/scripts/WebScriptServletRequest.java | 70 ++++- .../web/scripts/WebScriptServletRuntime.java | 12 +- .../scripts/facebook/FacebookAPIRuntime.java | 71 +++++ .../scripts/facebook/FacebookAPIServlet.java | 76 +++++ .../scripts/facebook/FacebookAppModel.java | 40 +++ .../facebook/FacebookAuthenticator.java | 102 ++++++ .../web/scripts/facebook/FacebookModel.java | 133 ++++++++ .../web/scripts/facebook/FacebookService.java | 118 +++++++ .../web/scripts/facebook/FacebookServlet.java | 74 +++++ .../facebook/FacebookServletRequest.java | 125 ++++++++ .../facebook/FacebookServletRuntime.java | 107 +++++++ .../alfresco/web/scripts/jsf/UIWebScript.java | 2 +- .../web/scripts/portlet/WebScriptPortlet.java | 2 +- source/web/WEB-INF/web.xml | 30 ++ 25 files changed, 1247 insertions(+), 169 deletions(-) create mode 100644 config/alfresco/templates/webscripts/fbml.status.ftl create mode 100644 source/java/org/alfresco/web/scripts/facebook/FacebookAPIRuntime.java create mode 100644 source/java/org/alfresco/web/scripts/facebook/FacebookAPIServlet.java create mode 100644 source/java/org/alfresco/web/scripts/facebook/FacebookAppModel.java create mode 100644 source/java/org/alfresco/web/scripts/facebook/FacebookAuthenticator.java create mode 100644 source/java/org/alfresco/web/scripts/facebook/FacebookModel.java create mode 100644 source/java/org/alfresco/web/scripts/facebook/FacebookService.java create mode 100644 source/java/org/alfresco/web/scripts/facebook/FacebookServlet.java create mode 100644 source/java/org/alfresco/web/scripts/facebook/FacebookServletRequest.java create mode 100644 source/java/org/alfresco/web/scripts/facebook/FacebookServletRuntime.java diff --git a/config/alfresco/templates/webscripts/fbml.status.ftl b/config/alfresco/templates/webscripts/fbml.status.ftl new file mode 100644 index 0000000000..9a0ba1cf2c --- /dev/null +++ b/config/alfresco/templates/webscripts/fbml.status.ftl @@ -0,0 +1,46 @@ + + +
+ + + + + + +
AlfrescoWeb Script Status ${status.code} - ${status.codeName}
+
+ +
Error:${status.codeName} (${status.code}) - ${status.codeDescription} +
  +
Message:${status.message!"<Not specified>"} + <#if status.exception?exists> +
  + <@recursestack status.exception/> + +
Server:Alfresco ${server.edition} v${server.version} schema ${server.schema} +
Time:${date?datetime} +
  +
+ +
+ + +<#macro recursestack exception> + <#if exception.cause?exists> + <@recursestack exception=exception.cause/> + + Exception:${exception.class.name}<#if exception.message?exists> - ${exception.message} +   + <#if exception.cause?exists == false> + <#list exception.stackTrace as element> + ${element} + + <#else> + ${exception.stackTrace[0]} + +   + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/scriptdump.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/scriptdump.get.html.ftl index 804a92aabb..b1b63dde14 100644 --- a/config/alfresco/templates/webscripts/org/alfresco/scriptdump.get.html.ftl +++ b/config/alfresco/templates/webscripts/org/alfresco/scriptdump.get.html.ftl @@ -24,7 +24,7 @@ URL Template:${URI} Format Style:${script.formatStyle} - Default Format:${script.defaultFormat} + Default Format:${script.defaultFormat!"[undefined}]"} Implementation:${script_class}

diff --git a/config/alfresco/web-scripts-application-context.xml b/config/alfresco/web-scripts-application-context.xml index 1141382111..ece3b74849 100644 --- a/config/alfresco/web-scripts-application-context.xml +++ b/config/alfresco/web-scripts-application-context.xml @@ -132,6 +132,7 @@ application/opensearchdescription+xml text/plain text/html + text/html @@ -185,6 +186,17 @@ + + + + + + + + + + + diff --git a/source/java/org/alfresco/web/app/servlet/PageRendererServlet.java b/source/java/org/alfresco/web/app/servlet/PageRendererServlet.java index 2086bc626b..568e21a2b4 100644 --- a/source/java/org/alfresco/web/app/servlet/PageRendererServlet.java +++ b/source/java/org/alfresco/web/app/servlet/PageRendererServlet.java @@ -63,6 +63,8 @@ import org.alfresco.web.scripts.WebScriptRequest; import org.alfresco.web.scripts.WebScriptResponse; import org.alfresco.web.scripts.WebScriptRuntime; import org.alfresco.web.scripts.WebScriptServlet; +import org.alfresco.web.scripts.WebScriptServletRequest; +import org.alfresco.web.scripts.WebScriptServletResponse; import org.alfresco.web.scripts.WebScriptURLRequest; import org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication; import org.apache.commons.logging.Log; @@ -529,7 +531,7 @@ public class PageRendererServlet extends WebScriptServlet } @Override - protected boolean authenticate(RequiredAuthentication required, boolean isGuest) + protected boolean authenticate(RequiredAuthentication required, boolean isGuest, WebScriptRequest req, WebScriptResponse res) { // TODO: what authentication here? return true; diff --git a/source/java/org/alfresco/web/scripts/AbstractWebScript.java b/source/java/org/alfresco/web/scripts/AbstractWebScript.java index 093c933074..1d8f65b5e8 100644 --- a/source/java/org/alfresco/web/scripts/AbstractWebScript.java +++ b/source/java/org/alfresco/web/scripts/AbstractWebScript.java @@ -29,13 +29,11 @@ import java.io.Writer; import java.util.Arrays; import java.util.Date; import java.util.HashMap; -import java.util.Iterator; import java.util.Map; import java.util.concurrent.locks.ReentrantReadWriteLock; import javax.servlet.http.HttpServletResponse; -import org.alfresco.repo.jscript.Scopeable; import org.alfresco.repo.jscript.ScriptableHashMap; import org.alfresco.repo.template.AbsoluteUrlMethod; import org.alfresco.service.ServiceRegistry; @@ -50,10 +48,10 @@ import org.alfresco.service.cmr.repository.TemplateService; import org.alfresco.service.descriptor.DescriptorService; import org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication; import org.alfresco.web.scripts.WebScriptDescription.RequiredTransaction; +import org.alfresco.web.scripts.facebook.FacebookModel; +import org.alfresco.web.scripts.facebook.FacebookServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.mozilla.javascript.Context; -import org.mozilla.javascript.Scriptable; /** @@ -305,14 +303,21 @@ public abstract class AbstractWebScript implements WebScript // add web script context model.put("args", createScriptArgs(req)); model.put("argsM", createScriptArgsM(req)); - if (req instanceof WebScriptServletRequest) - { - model.put("formdata", new FormData(((WebScriptServletRequest)req).getHttpServletRequest())); - } model.put("guest", req.isGuest()); model.put("url", new URLModel(req)); model.put("server", new ServerModel(descriptorService.getServerDescriptor())); + // TODO: Refactor creation of runtime specific parameters with + // Web Script F/W extraction + if (req instanceof WebScriptServletRequest) + { + model.put("formdata", ((WebScriptServletRequest)req).getFormData()); + } + if (req instanceof FacebookServletRequest) + { + model.put("facebook", new FacebookModel(((FacebookServletRequest)req))); + } + // add custom model if (customModel != null) { @@ -366,13 +371,20 @@ public abstract class AbstractWebScript implements WebScript model.put("url", new URLModel(req)); model.put("webscript", getDescription()); model.put("server", new ServerModel(descriptorService.getServerDescriptor())); - + + // TODO: Refactor creation of runtime specific parameters with + // Web Script F/W extraction + if (req instanceof FacebookServletRequest) + { + model.put("facebook", new FacebookModel(((FacebookServletRequest)req))); + } + // add template support model.put("absurl", new AbsoluteUrlMethod(req.getServerPath())); model.put("scripturl", new ScriptUrlMethod(req, res)); model.put("clienturlfunction", new ClientUrlFunctionMethod(res)); model.put("date", new Date()); - model.put(TemplateService.KEY_IMAGE_RESOLVER, getWebScriptRegistry().getTemplateImageResolver()); + model.put(TemplateService.KEY_IMAGE_RESOLVER, getWebScriptRegistry().getTemplateImageResolver()); // add custom model if (customModel != null) diff --git a/source/java/org/alfresco/web/scripts/BasicHttpAuthenticator.java b/source/java/org/alfresco/web/scripts/BasicHttpAuthenticator.java index d3db1bac21..1c00e7937f 100644 --- a/source/java/org/alfresco/web/scripts/BasicHttpAuthenticator.java +++ b/source/java/org/alfresco/web/scripts/BasicHttpAuthenticator.java @@ -60,7 +60,7 @@ public class BasicHttpAuthenticator implements WebScriptServletAuthenticator /* (non-Javadoc) * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation) */ - public boolean authenticate(RequiredAuthentication required, boolean isGuest, HttpServletRequest req, HttpServletResponse res) + public boolean authenticate(RequiredAuthentication required, boolean isGuest, WebScriptServletRequest preq, WebScriptServletResponse pres) { boolean authorized = false; @@ -68,6 +68,8 @@ public class BasicHttpAuthenticator implements WebScriptServletAuthenticator // validate credentials // + HttpServletRequest req = preq.getHttpServletRequest(); + HttpServletResponse res = pres.getHttpServletResponse(); String authorization = req.getHeader("Authorization"); String ticket = req.getParameter("alf_ticket"); diff --git a/source/java/org/alfresco/web/scripts/FormData.java b/source/java/org/alfresco/web/scripts/FormData.java index 3f1c69a824..6e21c08e1e 100644 --- a/source/java/org/alfresco/web/scripts/FormData.java +++ b/source/java/org/alfresco/web/scripts/FormData.java @@ -27,7 +27,9 @@ package org.alfresco.web.scripts; import java.io.IOException; import java.io.Serializable; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import javax.servlet.http.HttpServletRequest; @@ -55,8 +57,10 @@ public class FormData implements Serializable, Scopeable private Scriptable scope; private HttpServletRequest req; private ServletFileUpload upload; - private List files = null; - + private Map fields = null; + private Map parameters = null; + private Map files = null; + /** * Construct * @@ -70,24 +74,19 @@ public class FormData implements Serializable, Scopeable /* (non-Javadoc) * @see org.alfresco.repo.jscript.Scopeable#setScope(org.mozilla.javascript.Scriptable) */ - public void setScope(Scriptable scope) - { - this.scope = scope; - } - - /** - * Determine if multi-part form data has been provided - * - * @return true => multi-part - */ - public boolean getIsMultiPart() - { - return upload.isMultipartContent(req); - } - - public boolean jsGet_isMultipart() + public void setScope(Scriptable scope) { - return getIsMultiPart(); + this.scope = scope; + } + + /** + * Determine if multi-part form data has been provided + * + * @return true => multi-part + */ + public boolean getIsMultiPart() + { + return upload.isMultipartContent(req); } /** @@ -96,107 +95,143 @@ public class FormData implements Serializable, Scopeable * @param name field to look for * @return true => form data contains field */ - public boolean hasField(String name) - { - List files = getFiles(); - for (FileItem file : files) - { - if (file.getFieldName().equals(name)) - { - return true; - } - } - return false; - } + public boolean hasField(String name) + { + Map fields = getFieldsMap(); + return fields.containsKey(name); + } - /** - * Gets the Form fields - * - * @return array of FormField - */ + /** + * Gets the Form fields + * + * @return array of FormField + */ public Scriptable getFields() { - List files = getFiles(); - Object[] fields = new Object[files.size()]; - int i = 0; - for (FileItem file : files) - { - fields[i++] = new FormField(file); - } + Map fieldsMap = getFieldsMap(); + Object[] fields = new Object[fieldsMap.values().size()]; + fieldsMap.values().toArray(fields); return Context.getCurrentContext().newArray(this.scope, fields); } - public Scriptable jsGet_fields() + /*package*/ Map getParameters() { - return getFields(); + return getParametersMap(); } - + + /*package*/ Map getFiles() + { + return getFilesMap(); + } + /** * Helper to parse servlet request form data * * @return parsed form data */ - private List getFiles() - { - // NOTE: This class is not thread safe - it is expected to be constructed on each thread. - if (files == null) - { - FileItemFactory factory = new DiskFileItemFactory(); - upload = new ServletFileUpload(factory); - try - { - files = upload.parseRequest(req); - } + private Map getFieldsMap() + { + // NOTE: This class is not thread safe - it is expected to be constructed on each thread. + if (fields == null) + { + FileItemFactory factory = new DiskFileItemFactory(); + upload = new ServletFileUpload(factory); + try + { + List fileItems = upload.parseRequest(req); + fields = new HashMap(); + for (FileItem fileItem : fileItems) + { + FormField formField = new FormField(fileItem); + fields.put(fileItem.getFieldName(), formField); + } + } catch(FileUploadException e) { // NOTE: assume no files can be located - files = Collections.EMPTY_LIST; + fields = Collections.emptyMap(); } - } - return files; - } + } + return fields; + } + private Map getParametersMap() + { + if (parameters == null) + { + Map fields = getFieldsMap(); + parameters = new HashMap(); + for (Map.Entry entry : fields.entrySet()) + { + FormField field = entry.getValue(); + if (!field.getIsFile()) + { + parameters.put(entry.getKey(), field.getValue()); + } + } + } + return parameters; + } + + private Map getFilesMap() + { + if (files == null) + { + Map fields = getFieldsMap(); + files = new HashMap(); + for (Map.Entry entry : fields.entrySet()) + { + FormField field = entry.getValue(); + if (field.getIsFile()) + { + files.put(entry.getKey(), field.getContent()); + } + } + } + return files; + } + - /** - * Form Field - * - * @author davidc - */ - public class FormField implements Serializable - { - private FileItem file; + /** + * Form Field + * + * @author davidc + */ + public class FormField implements Serializable + { + private FileItem file; - /** - * Construct - * - * @param file - */ - public FormField(FileItem file) - { - this.file = file; - } - - /** - * @return field name - */ - public String getName() - { - return file.getFieldName(); - } - - public String jsGet_name() - { - return getName(); - } - - /** - * @return true => field represents a file - */ - public boolean getIsFile() - { - return !file.isFormField(); - } - + /** + * Construct + * + * @param file + */ + public FormField(FileItem file) + { + this.file = file; + } + + /** + * @return field name + */ + public String getName() + { + return file.getFieldName(); + } + + public String jsGet_name() + { + return getName(); + } + + /** + * @return true => field represents a file + */ + public boolean getIsFile() + { + return !file.isFormField(); + } + public boolean jsGet_isFile() { return getIsFile(); @@ -206,9 +241,9 @@ public class FormData implements Serializable, Scopeable * @return field value (for file, attempts conversion to string) */ public String getValue() - { - return file.getString(); - } + { + return file.getString(); + } public String jsGet_value() { @@ -218,30 +253,30 @@ public class FormData implements Serializable, Scopeable /** * @return field as content */ - public ScriptContent getContent() - { - try - { - return new ScriptNode.ScriptContentStream(file.getInputStream(), getMimetype(), null); - } - catch(IOException e) - { - return null; - } - } + public ScriptContent getContent() + { + try + { + return new ScriptNode.ScriptContentStream(file.getInputStream(), getMimetype(), null); + } + catch(IOException e) + { + return null; + } + } - public ScriptContent jsGet_content() + public ScriptContent jsGet_content() { return getContent(); } - /** - * @return mimetype - */ - public String getMimetype() - { - return file.getContentType(); - } + /** + * @return mimetype + */ + public String getMimetype() + { + return file.getContentType(); + } public String jsGet_mimetype() { @@ -251,16 +286,16 @@ public class FormData implements Serializable, Scopeable /** * @return filename (only for file fields, otherwise null) */ - public String getFilename() - { - return file.getName(); - } - + public String getFilename() + { + return file.getName(); + } + public String jsGet_filename() { return getFilename(); } - } - + } + } diff --git a/source/java/org/alfresco/web/scripts/WebClientAuthenticator.java b/source/java/org/alfresco/web/scripts/WebClientAuthenticator.java index bcf09e7503..2f3d463cd1 100644 --- a/source/java/org/alfresco/web/scripts/WebClientAuthenticator.java +++ b/source/java/org/alfresco/web/scripts/WebClientAuthenticator.java @@ -63,7 +63,7 @@ public class WebClientAuthenticator implements WebScriptServletAuthenticator, Se /* (non-Javadoc) * @see org.alfresco.web.scripts.WebScriptServletAuthenticator#authenticate(org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication, boolean, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ - public boolean authenticate(RequiredAuthentication required, boolean isGuest, HttpServletRequest req, HttpServletResponse res) + public boolean authenticate(RequiredAuthentication required, boolean isGuest, WebScriptServletRequest preq, WebScriptServletResponse pres) { AuthenticationStatus status = null; @@ -72,6 +72,8 @@ public class WebClientAuthenticator implements WebScriptServletAuthenticator, Se // // validate credentials // + HttpServletRequest req = preq.getHttpServletRequest(); + HttpServletResponse res = pres.getHttpServletResponse(); String ticket = req.getParameter("ticket"); if (logger.isDebugEnabled()) diff --git a/source/java/org/alfresco/web/scripts/WebScriptRuntime.java b/source/java/org/alfresco/web/scripts/WebScriptRuntime.java index a921c429b2..3a9d266143 100644 --- a/source/java/org/alfresco/web/scripts/WebScriptRuntime.java +++ b/source/java/org/alfresco/web/scripts/WebScriptRuntime.java @@ -25,6 +25,8 @@ package org.alfresco.web.scripts; import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; import java.util.Date; import java.util.HashMap; import java.util.Map; @@ -162,6 +164,13 @@ public abstract class WebScriptRuntime { if (logger.isInfoEnabled()) logger.info("Caught exception & redirecting to status template: " + e.getMessage()); + if (logger.isDebugEnabled()) + { + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + e.printStackTrace(printWriter); + logger.debug("Caught exception: " + writer.toString()); + } // extract status code, if specified int statusCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR; @@ -189,10 +198,10 @@ public abstract class WebScriptRuntime // NOTE: search order... // 1) root located .ftl // 2) root located status.ftl - String templatePath = "/" + statusCode + ".ftl"; + String templatePath = getStatusCodeTemplate(statusCode); if (!registry.getTemplateProcessor().hasTemplate(templatePath)) { - templatePath = "/status.ftl"; + templatePath = getStatusTemplate(); if (!registry.getTemplateProcessor().hasTemplate(templatePath)) { throw new WebScriptException("Failed to find status template " + templatePath + " (format: " + WebScriptResponse.HTML_FORMAT + ")"); @@ -273,7 +282,7 @@ public abstract class WebScriptRuntime // // Apply appropriate authentication to Web Script invocation // - if (authenticate(required, isGuest)) + if (authenticate(required, isGuest, scriptReq, scriptRes)) { if (required == RequiredAuthentication.admin && !authorityService.hasAdminAuthority()) { @@ -404,7 +413,8 @@ public abstract class WebScriptRuntime * * @return true if authorised, false otherwise */ - protected abstract boolean authenticate(RequiredAuthentication required, boolean isGuest); + // TODO: DC - This method to be refactored during Web Script F/W extraction + protected abstract boolean authenticate(RequiredAuthentication required, boolean isGuest, WebScriptRequest req, WebScriptResponse res); /** * Pre-execution hook @@ -429,4 +439,15 @@ public abstract class WebScriptRuntime protected void postExecute(WebScriptRequest scriptReq, WebScriptResponse scriptRes) { } + + protected String getStatusCodeTemplate(int statusCode) + { + return "/" + statusCode + ".ftl"; + } + + protected String getStatusTemplate() + { + return "/status.ftl"; + } + } diff --git a/source/java/org/alfresco/web/scripts/WebScriptServlet.java b/source/java/org/alfresco/web/scripts/WebScriptServlet.java index 45413436de..1ac920e912 100644 --- a/source/java/org/alfresco/web/scripts/WebScriptServlet.java +++ b/source/java/org/alfresco/web/scripts/WebScriptServlet.java @@ -76,7 +76,7 @@ public class WebScriptServlet extends HttpServlet String authenticatorId = getInitParameter("authenticator"); if (authenticatorId == null || authenticatorId.length() == 0) { - authenticatorId = "webscripts.authenticator.webclient"; + authenticatorId = getDefaultAuthenticator(); } Object bean = context.getBean(authenticatorId); if (bean == null || !(bean instanceof WebScriptServletAuthenticator)) @@ -88,6 +88,9 @@ public class WebScriptServlet extends HttpServlet // retrieve host server configuration Config config = configService.getConfig("Server"); serverConfig = (ServerConfigElement)config.getConfigElement(ServerConfigElement.CONFIG_ELEMENT_ID); + + // servlet specific initialisation + initServlet(context); } @@ -106,4 +109,21 @@ public class WebScriptServlet extends HttpServlet runtime.executeScript(); } + /** + * Servlet specific initialisation + * + * @param context + */ + protected void initServlet(ApplicationContext context) + { + // NOOP + } + + /** + * @return default authenticator (bean name) + */ + protected String getDefaultAuthenticator() + { + return "webscripts.authenticator.webclient"; + } } diff --git a/source/java/org/alfresco/web/scripts/WebScriptServletAuthenticator.java b/source/java/org/alfresco/web/scripts/WebScriptServletAuthenticator.java index 98099025d9..093954f25d 100644 --- a/source/java/org/alfresco/web/scripts/WebScriptServletAuthenticator.java +++ b/source/java/org/alfresco/web/scripts/WebScriptServletAuthenticator.java @@ -24,9 +24,6 @@ */ package org.alfresco.web.scripts; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - import org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication; /** @@ -46,5 +43,6 @@ public interface WebScriptServletAuthenticator * * @return true if authorised to execute the script, false otherwise */ - public boolean authenticate(RequiredAuthentication required, boolean isGuest, HttpServletRequest req, HttpServletResponse res); + // TODO: DC - This method to be refactored during Web Script F/W extraction + public boolean authenticate(RequiredAuthentication required, boolean isGuest, WebScriptServletRequest req, WebScriptServletResponse res); } diff --git a/source/java/org/alfresco/web/scripts/WebScriptServletRequest.java b/source/java/org/alfresco/web/scripts/WebScriptServletRequest.java index fd8e168386..9263afa72a 100644 --- a/source/java/org/alfresco/web/scripts/WebScriptServletRequest.java +++ b/source/java/org/alfresco/web/scripts/WebScriptServletRequest.java @@ -31,6 +31,8 @@ import java.util.Set; import javax.servlet.http.HttpServletRequest; import org.alfresco.web.config.ServerConfigElement; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; /** @@ -40,6 +42,9 @@ import org.alfresco.web.config.ServerConfigElement; */ public class WebScriptServletRequest extends WebScriptRequestImpl { + // Logger + private static final Log logger = LogFactory.getLog(WebScriptServletRequest.class); + /** Server Config */ private ServerConfigElement serverConfig; @@ -48,7 +53,10 @@ public class WebScriptServletRequest extends WebScriptRequestImpl /** Service bound to this request */ private WebScriptMatch serviceMatch; - + + /** Form data associated with multipart/form-data */ + private FormData formData; + /** * Construct @@ -56,7 +64,7 @@ public class WebScriptServletRequest extends WebScriptRequestImpl * @param req * @param serviceMatch */ - WebScriptServletRequest(HttpServletRequest req, WebScriptMatch serviceMatch) + public WebScriptServletRequest(HttpServletRequest req, WebScriptMatch serviceMatch) { this(null, req, serviceMatch); } @@ -68,11 +76,20 @@ public class WebScriptServletRequest extends WebScriptRequestImpl * @param req * @param serviceMatch */ - WebScriptServletRequest(ServerConfigElement serverConfig, HttpServletRequest req, WebScriptMatch serviceMatch) + public WebScriptServletRequest(ServerConfigElement serverConfig, HttpServletRequest req, WebScriptMatch serviceMatch) { this.serverConfig = serverConfig; this.req = req; this.serviceMatch = serviceMatch; + String contentType = req.getContentType(); + + if (logger.isDebugEnabled()) + logger.debug("Content Type: " + contentType); + + if (contentType != null && contentType.startsWith("multipart/form-data")) + { + formData = new FormData(req); + } } /** @@ -165,10 +182,20 @@ public class WebScriptServletRequest extends WebScriptRequestImpl */ public String[] getParameterNames() { - Set keys = req.getParameterMap().keySet(); - String[] names = new String[keys.size()]; - keys.toArray(names); - return names; + if (formData == null) + { + Set keys = req.getParameterMap().keySet(); + String[] names = new String[keys.size()]; + keys.toArray(names); + return names; + } + else + { + Set keys = formData.getParameters().keySet(); + String[] names = new String[keys.size()]; + keys.toArray(names); + return names; + } } /* (non-Javadoc) @@ -176,7 +203,14 @@ public class WebScriptServletRequest extends WebScriptRequestImpl */ public String getParameter(String name) { - return req.getParameter(name); + if (formData == null) + { + return req.getParameter(name); + } + else + { + return formData.getParameters().get(name); + } } /* (non-Javadoc) @@ -184,7 +218,15 @@ public class WebScriptServletRequest extends WebScriptRequestImpl */ public String[] getParameterValues(String name) { - return req.getParameterValues(name); + if (formData == null) + { + return req.getParameterValues(name); + } + else + { + String value = formData.getParameters().get(name); + return (value == null ) ? new String[] {} : new String[] {value}; + } } /* (non-Javadoc) @@ -302,4 +344,14 @@ public class WebScriptServletRequest extends WebScriptRequestImpl return Boolean.valueOf(forceSuccess); } + /** + * Gets the Form data associated with this request + * + * @return form data, or null if request is not multipart/form-data encoded + */ + public FormData getFormData() + { + return formData; + } + } diff --git a/source/java/org/alfresco/web/scripts/WebScriptServletRuntime.java b/source/java/org/alfresco/web/scripts/WebScriptServletRuntime.java index b91a20b66f..f4fff0112a 100644 --- a/source/java/org/alfresco/web/scripts/WebScriptServletRuntime.java +++ b/source/java/org/alfresco/web/scripts/WebScriptServletRuntime.java @@ -42,10 +42,10 @@ import org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication; */ public class WebScriptServletRuntime extends WebScriptRuntime { - private HttpServletRequest req; - private HttpServletResponse res; - private WebScriptServletAuthenticator authenticator; - private ServerConfigElement serverConfig; + protected HttpServletRequest req; + protected HttpServletResponse res; + protected WebScriptServletAuthenticator authenticator; + protected ServerConfigElement serverConfig; /** @@ -137,12 +137,12 @@ public class WebScriptServletRuntime extends WebScriptRuntime * @see org.alfresco.web.scripts.WebScriptRuntime#authenticate(org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication, boolean) */ @Override - protected boolean authenticate(RequiredAuthentication required, boolean isGuest) + protected boolean authenticate(RequiredAuthentication required, boolean isGuest, WebScriptRequest req, WebScriptResponse res) { boolean authorised = true; if (authenticator != null) { - authorised = authenticator.authenticate(required, isGuest, req, res); + authorised = authenticator.authenticate(required, isGuest, (WebScriptServletRequest)req, (WebScriptServletResponse)res); } return authorised; } diff --git a/source/java/org/alfresco/web/scripts/facebook/FacebookAPIRuntime.java b/source/java/org/alfresco/web/scripts/facebook/FacebookAPIRuntime.java new file mode 100644 index 0000000000..2407a3167d --- /dev/null +++ b/source/java/org/alfresco/web/scripts/facebook/FacebookAPIRuntime.java @@ -0,0 +1,71 @@ +/* + * 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 javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.service.ServiceRegistry; +import org.alfresco.web.config.ServerConfigElement; +import org.alfresco.web.scripts.WebScriptMatch; +import org.alfresco.web.scripts.WebScriptRegistry; +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptServletAuthenticator; +import org.alfresco.web.scripts.WebScriptServletRuntime; + + +/** + * HTTP Servlet Web Script Runtime + * + * @author davidc + */ +public class FacebookAPIRuntime extends WebScriptServletRuntime +{ + + /** + * Construct + * + * @param registry + * @param serviceRegistry + * @param authenticator + * @param req + * @param res + */ + public FacebookAPIRuntime(WebScriptRegistry registry, ServiceRegistry serviceRegistry, WebScriptServletAuthenticator authenticator, + HttpServletRequest req, HttpServletResponse res, ServerConfigElement serverConfig) + { + super(registry, serviceRegistry, authenticator, req, res, serverConfig); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRuntime#createRequest(org.alfresco.web.scripts.WebScriptMatch) + */ + @Override + protected WebScriptRequest createRequest(WebScriptMatch match) + { + return new FacebookServletRequest(serverConfig, req, match, getScriptUrl()); + } + +} diff --git a/source/java/org/alfresco/web/scripts/facebook/FacebookAPIServlet.java b/source/java/org/alfresco/web/scripts/facebook/FacebookAPIServlet.java new file mode 100644 index 0000000000..fc8b2064c5 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/facebook/FacebookAPIServlet.java @@ -0,0 +1,76 @@ +/* + * 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; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.web.scripts.WebScriptRuntime; +import org.alfresco.web.scripts.WebScriptServlet; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +/** + * Web Script API entry point (with Facebook authentication) + * + * @author davidc + */ +public class FacebookAPIServlet extends WebScriptServlet +{ + private static final long serialVersionUID = 4209892938069597860L; + + // Logger + private static final Log logger = LogFactory.getLog(FacebookAPIServlet.class); + + + /* + * (non-Javadoc) + * + * @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, + * javax.servlet.http.HttpServletResponse) + */ + protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException + { + if (logger.isDebugEnabled()) + logger.debug("Processing facebook api request (" + req.getMethod() + ") " + req.getRequestURL() + (req.getQueryString() != null ? "?" + req.getQueryString() : "")); + + WebScriptRuntime runtime = new FacebookAPIRuntime(registry, serviceRegistry, authenticator, req, res, serverConfig); + runtime.executeScript(); + } + + /** + * @return default authenticator (bean name) + */ + @Override + protected String getDefaultAuthenticator() + { + return "facebook.authenticator"; + } + +} diff --git a/source/java/org/alfresco/web/scripts/facebook/FacebookAppModel.java b/source/java/org/alfresco/web/scripts/facebook/FacebookAppModel.java new file mode 100644 index 0000000000..c32c00083a --- /dev/null +++ b/source/java/org/alfresco/web/scripts/facebook/FacebookAppModel.java @@ -0,0 +1,40 @@ +package org.alfresco.web.scripts.facebook; + +public class FacebookAppModel +{ + String appId; + String apiKey; + String secretKey; + + + public FacebookAppModel(String apiKey) + { + this.apiKey = apiKey; + } + + public String getApiKey() + { + return apiKey; + } + + public String getSecret() + { + return secretKey; + } + + public void setSecret(String secretKey) + { + this.secretKey = secretKey; + } + + public String getId() + { + return appId; + } + + 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 new file mode 100644 index 0000000000..e2a19c4020 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/facebook/FacebookAuthenticator.java @@ -0,0 +1,102 @@ +/* + * 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; + +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.web.scripts.WebScriptException; +import org.alfresco.web.scripts.WebScriptServletAuthenticator; +import org.alfresco.web.scripts.WebScriptServletRequest; +import org.alfresco.web.scripts.WebScriptServletResponse; +import org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +public class FacebookAuthenticator implements WebScriptServletAuthenticator +{ + // Logger + private static final Log logger = LogFactory.getLog(FacebookAuthenticator.class); + + // FBML for Facebook login redirect + private static final String LOGIN_REDIRECT = ""; + + + /* (non-Javadoc) + * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation) + */ + public boolean authenticate(RequiredAuthentication required, boolean isGuest, WebScriptServletRequest req, WebScriptServletResponse res) + { + // TODO: Refactor with Web Script F/W Extraction + FacebookServletRequest fbreq = (FacebookServletRequest)req; + + String sessionKey = fbreq.getSessionKey(); + String user = fbreq.getUserId(); + + if (logger.isDebugEnabled()) + { + logger.debug("fb_sig_session_key = '" + sessionKey + "'"); + logger.debug("fb_sig_user = '" + user + "'"); + } + + if ((sessionKey == null || sessionKey.length() == 0) || (user == null || user.length() == 0)) + { + // session has not been established, redirect to login + + String apiKey = fbreq.getApiKey(); + String canvas = (fbreq.isInCanvas()) ? "&canvas" : ""; + + if (logger.isDebugEnabled()) + { + logger.debug("fb_sig_api_key = '" + apiKey + "'"); + logger.debug("fb_sig_in_canvas = '" + canvas + "'"); + } + + try + { + String redirect = String.format(LOGIN_REDIRECT, apiKey, canvas); + + if (logger.isDebugEnabled()) + logger.debug("Facebook session not established; redirecting via " + redirect); + + res.getWriter().write(redirect); + } + catch (IOException e) + { + throw new WebScriptException("Redirect to login failed", e); + } + return false; + } + + if (logger.isDebugEnabled()) + logger.debug("Facebook session established; authenticating as user " + user); + + // session has been established, authenticate as Facebook user id + AuthenticationUtil.setCurrentUser(user); + return true; + } + +} diff --git a/source/java/org/alfresco/web/scripts/facebook/FacebookModel.java b/source/java/org/alfresco/web/scripts/facebook/FacebookModel.java new file mode 100644 index 0000000000..05fce4468c --- /dev/null +++ b/source/java/org/alfresco/web/scripts/facebook/FacebookModel.java @@ -0,0 +1,133 @@ +package org.alfresco.web.scripts.facebook; + +import java.io.IOException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; + +import com.facebook.api.FacebookException; +import com.facebook.api.FacebookRestClient; + + +public class FacebookModel +{ + // Logger + private static final Log logger = LogFactory.getLog(FacebookModel.class); + + private FacebookServletRequest req; + private FacebookRestClient client; + private String[] friends; + + public FacebookModel(FacebookServletRequest req) + { + this.req = req; + } + + private FacebookRestClient getClient() + { + if (client == null) + { + String apiKey = req.getApiKey(); + String secretKey = req.getSecretKey(); + String sessionKey = req.getSessionKey(); + if (sessionKey == null) + { + client = new FacebookRestClient(apiKey, secretKey); + } + else + { + client = new FacebookRestClient(apiKey, secretKey, sessionKey); + } + } + return client; + } + + public String[] getFriends() + { + if (friends == null) + { + friends = req.getFriends(); + if (friends == null) + { + try + { + Document friendsDoc = getClient().friends_get(); + NodeList uids = friendsDoc.getElementsByTagName("uid"); + friends = new String[uids.getLength()]; + for (int i = 0; i < uids.getLength(); i++) + { + friends[i] = uids.item(i).getTextContent(); + } + } + catch(Exception e) + { + friends = new String[0]; + } + } + } + return friends; + } + + public String getUser() + { + return req.getUserId(); + } + + public String getAppId() + { + return req.getAppId(); + } + + public String getSessionKey() + { + return req.getSessionKey(); + } + + public String getApiKey() + { + return req.getApiKey(); + } + + public String getCanvasPath() + { + return req.getCanvasPath(); + } + + public String getCanvasURL() + { + return "http://apps.facebook.com/" + getCanvasPath(); + } + + public String getPageURL() + { + return "http://apps.facebook.com" + req.getPathInfo(); + } + + 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 new file mode 100644 index 0000000000..a22ddd1d45 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/facebook/FacebookService.java @@ -0,0 +1,118 @@ +package org.alfresco.web.scripts.facebook; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import org.alfresco.service.cmr.repository.ScriptLocation; +import org.alfresco.web.scripts.WebScriptContext; +import org.alfresco.web.scripts.WebScriptException; +import org.alfresco.web.scripts.WebScriptRegistry; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +public class FacebookService +{ + // Logger + private static final Log logger = LogFactory.getLog(FacebookService.class); + + // Facebook Application Cache + private Map apps = new HashMap(); + private ReentrantReadWriteLock appsLock = new ReentrantReadWriteLock(); + + private WebScriptRegistry registry; + private WebScriptContext context; + + + public void setRegistry(WebScriptRegistry registry) + { + this.registry = registry; + } + + + + FacebookAppModel getAppModel(String apiKey) + { + FacebookAppModel facebookApp = null; + appsLock.readLock().lock(); + + try + { + facebookApp = apps.get(apiKey); + if (facebookApp == null) + { + // Upgrade read lock to write lock + appsLock.readLock().unlock(); + appsLock.writeLock().lock(); + + try + { + // Check again + facebookApp = apps.get(apiKey); + if (facebookApp == null) + { + if (logger.isDebugEnabled()) + logger.debug("Initialising Facebook Application '" + apiKey + "'"); + + // Locate app initialisation script in web script store + String appPath = "/com/facebook/_apps/app." + apiKey + ".js"; + ScriptLocation appScript = registry.getScriptProcessor().findScript(appPath); + if (appScript == null) + { + throw new WebScriptException("Unable to locate application initialisation script '" + appPath + "'"); + } + + // Execute app initialisation script + Map model = new HashMap(); + FacebookAppModel app = new FacebookAppModel(apiKey); + model.put("app", app); + registry.getScriptProcessor().executeScript(appScript, model); + + // Validate initialisation + if (app.getSecret() == null) + { + throw new WebScriptException("Secret key for application '" + apiKey + "' has not been specified."); + } + if (app.getApiKey() == null) + { + throw new WebScriptException("Application Id for application '" + apiKey + "' has not been specified."); + } + + apps.put(apiKey, app); + facebookApp = app; + } + } + finally + { + // Downgrade lock to read + appsLock.readLock().lock(); + appsLock.writeLock().unlock(); + } + } + return facebookApp; + } + finally + { + appsLock.readLock().unlock(); + } + } + + public Map getAppModels() + { + return apps; + } + + public void reset() + { + appsLock.writeLock().lock(); + try + { + apps.clear(); + } + finally + { + 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 new file mode 100644 index 0000000000..ce69ff7620 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/facebook/FacebookServlet.java @@ -0,0 +1,74 @@ +/* + * 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; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.web.scripts.WebScriptRuntime; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.context.ApplicationContext; + + +/** + * Facebook Canvas Page Requests + * + * @author davidc + */ +public class FacebookServlet extends FacebookAPIServlet +{ + // Logger + private static final Log logger = LogFactory.getLog(FacebookServlet.class); + + // Component Dependencies + protected FacebookService facebookService; + + + /* + * (non-Javadoc) + * + * @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, + * javax.servlet.http.HttpServletResponse) + */ + protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException + { + if (logger.isDebugEnabled()) + logger.debug("Processing facebook canvas (" + req.getMethod() + ") " + req.getRequestURL() + (req.getQueryString() != null ? "?" + req.getQueryString() : "")); + + WebScriptRuntime runtime = new FacebookServletRuntime(registry, serviceRegistry, authenticator, req, res, serverConfig, facebookService); + runtime.executeScript(); + } + + @Override + protected void initServlet(ApplicationContext context) + { + facebookService = (FacebookService)context.getBean("facebook.service"); + } + +} diff --git a/source/java/org/alfresco/web/scripts/facebook/FacebookServletRequest.java b/source/java/org/alfresco/web/scripts/facebook/FacebookServletRequest.java new file mode 100644 index 0000000000..d92c7f9a84 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/facebook/FacebookServletRequest.java @@ -0,0 +1,125 @@ +/* + * 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 javax.servlet.http.HttpServletRequest; + +import org.alfresco.web.config.ServerConfigElement; +import org.alfresco.web.scripts.WebScriptException; +import org.alfresco.web.scripts.WebScriptMatch; +import org.alfresco.web.scripts.WebScriptServletRequest; + + +/** + * HTTP Servlet Web Script Request + * + * @author davidc + */ +public class FacebookServletRequest extends WebScriptServletRequest +{ + private String appId; + private String secretKey; + private String pathInfo; + + + /** + * Construct + * + * @param serverConfig + * @param req + * @param serviceMatch + */ + public FacebookServletRequest(ServerConfigElement serverConfig, HttpServletRequest req, WebScriptMatch serviceMatch, String pathInfo) + { + super(serverConfig, req, serviceMatch); + this.pathInfo = pathInfo; + } + + /*package*/ void setSecretKey(String secretKey) + { + this.secretKey = secretKey; + } + + /*package*/ void setAppId(String appId) + { + this.appId = appId; + } + + public String getApiKey() + { + return getParameter("fb_sig_api_key"); + } + + public String getUserId() + { + return getParameter("fb_sig_user"); + } + + public String getSessionKey() + { + return getParameter("fb_sig_session_key"); + } + + public boolean isInCanvas() + { + String canvas = getParameter("fb_sig_api_key"); + return (canvas == null || canvas.equals("1")); + } + + public String getSecretKey() + { + return secretKey; + } + + public String getAppId() + { + return appId; + } + + public String getCanvasPath() + { + String pathInfo = getPathInfo(); + String[] pathSegments = pathInfo.split("/"); + if (pathSegments.length < 3) + { + throw new WebScriptException("Cannot establish Facebook Canvas Page URL from request " + getURL()); + } + return pathSegments[2]; + } + + public String[] getFriends() + { + String[] friends; + String friendsStr = getParameter("fb_sig_friends"); + friends = (friendsStr == null) ? new String[0] : friendsStr.split(","); + return friends; + } + + @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 new file mode 100644 index 0000000000..21cd785060 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/facebook/FacebookServletRuntime.java @@ -0,0 +1,107 @@ +/* + * 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 javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.service.ServiceRegistry; +import org.alfresco.web.config.ServerConfigElement; +import org.alfresco.web.scripts.WebScriptMatch; +import org.alfresco.web.scripts.WebScriptRegistry; +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptServletAuthenticator; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +/** + * HTTP Servlet Web Script Runtime + * + * @author davidc + */ +public class FacebookServletRuntime extends FacebookAPIRuntime +{ + // Logger + private static final Log logger = LogFactory.getLog(FacebookServletRuntime.class); + + protected FacebookService facebookService; + + /** + * Construct + * + * @param registry + * @param serviceRegistry + * @param authenticator + * @param req + * @param res + */ + public FacebookServletRuntime(WebScriptRegistry registry, ServiceRegistry serviceRegistry, WebScriptServletAuthenticator authenticator, + HttpServletRequest req, HttpServletResponse res, ServerConfigElement serverConfig, FacebookService facebookService) + { + super(registry, serviceRegistry, authenticator, req, res, serverConfig); + this.facebookService = facebookService; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRuntime#createRequest(org.alfresco.web.scripts.WebScriptMatch) + */ + @Override + protected WebScriptRequest createRequest(WebScriptMatch match) + { + FacebookServletRequest fbreq = new FacebookServletRequest(serverConfig, req, match, getScriptUrl()); + + if (match != null) + { + FacebookAppModel appModel = facebookService.getAppModel(fbreq.getApiKey()); + fbreq.setSecretKey(appModel.getSecret()); + fbreq.setAppId(appModel.getId()); + } + + if (logger.isDebugEnabled()) + logger.debug("Facebook request [apiKey=" + fbreq.getApiKey() + ", user=" + fbreq.getUserId() + ", session=" + fbreq.getSessionKey() + ", secret=" + fbreq.getSecretKey() + "]"); + + return fbreq; + } + + @Override + protected String getScriptUrl() + { + return "/facebook" + super.getScriptUrl(); + } + + @Override + protected String getStatusCodeTemplate(int statusCode) + { + return "/fbml." + statusCode + ".ftl"; + } + + @Override + protected String getStatusTemplate() + { + return "/fbml.status.ftl"; + } + +} diff --git a/source/java/org/alfresco/web/scripts/jsf/UIWebScript.java b/source/java/org/alfresco/web/scripts/jsf/UIWebScript.java index 85934e4510..9bccb02316 100644 --- a/source/java/org/alfresco/web/scripts/jsf/UIWebScript.java +++ b/source/java/org/alfresco/web/scripts/jsf/UIWebScript.java @@ -288,7 +288,7 @@ public class UIWebScript extends SelfRenderingComponent * @see org.alfresco.web.scripts.WebScriptRuntime#authenticate(org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication, boolean) */ @Override - protected boolean authenticate(RequiredAuthentication required, boolean isGuest) + protected boolean authenticate(RequiredAuthentication required, boolean isGuest, WebScriptRequest req, WebScriptResponse res) { // JSF component already in an authenticated environment as the // /faces servlet filter (or JSF portlet wrapper) is called first diff --git a/source/java/org/alfresco/web/scripts/portlet/WebScriptPortlet.java b/source/java/org/alfresco/web/scripts/portlet/WebScriptPortlet.java index fa81833b01..44abc6fd2e 100644 --- a/source/java/org/alfresco/web/scripts/portlet/WebScriptPortlet.java +++ b/source/java/org/alfresco/web/scripts/portlet/WebScriptPortlet.java @@ -285,7 +285,7 @@ public class WebScriptPortlet implements Portlet * @see org.alfresco.web.scripts.WebScriptRuntime#authenticate(org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication, boolean) */ @Override - protected boolean authenticate(RequiredAuthentication required, boolean isGuest) + protected boolean authenticate(RequiredAuthentication required, boolean isGuest, WebScriptRequest preq, WebScriptResponse pres) { return authenticator.authenticate(required, isGuest, req, res); } diff --git a/source/web/WEB-INF/web.xml b/source/web/WEB-INF/web.xml index 1321bb398c..ef61d7dea1 100644 --- a/source/web/WEB-INF/web.xml +++ b/source/web/WEB-INF/web.xml @@ -277,6 +277,16 @@ org.alfresco.web.scripts.WebScriptServlet + + facebookServlet + org.alfresco.web.scripts.facebook.FacebookServlet + + + + fbapiServlet + org.alfresco.web.scripts.facebook.FacebookAPIServlet + + proxyServlet org.alfresco.web.app.servlet.HTTPProxyServlet @@ -422,6 +432,26 @@ /168s/* + + facebookServlet + /facebook/* + + + + facebookServlet + /fb/* + + + + fbapiServlet + /fbservice/* + + + + fbapiServlet + /fbs/* + + proxyServlet /proxy