From fa8309b777a82c23fbfe87f29e8c821874d64593 Mon Sep 17 00:00:00 2001 From: David Caruana Date: Fri, 4 May 2007 15:11:19 +0000 Subject: [PATCH] Web Scripts as JSR-168 portlets git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5627 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../alfresco/portlets/doclist_get_html.ftl | 10 +- .../alfresco/portlets/mytasks_get_html.ftl | 12 +- .../repository/keywordsearch_get_desc.xml | 1 + .../repository/keywordsearch_get_portlet.ftl | 33 ++ .../web-scripts-application-context-test.xml | 6 +- .../web-scripts-application-context.xml | 31 +- .../web/scripts/AbstractWebScript.java | 8 +- .../web/scripts/BasicAuthenticator.java | 194 ----------- .../web/scripts/BasicHttpAuthenticator.java | 151 +++++++++ .../scripts/DeclarativeWebScriptRegistry.java | 136 ++------ .../alfresco/web/scripts/ScriptUrlMethod.java | 84 +++++ .../web/scripts/SystemAuthenticator.java | 94 ------ .../web/scripts/TestWebScriptServer.java | 15 +- .../web/scripts/TrustedAuthenticator.java | 91 ----- .../web/scripts/WebClientAuthenticator.java | 92 ++--- .../alfresco/web/scripts/WebScriptLogger.java | 73 ---- .../web/scripts/WebScriptRuntime.java | 318 ++++++++++++++++++ .../web/scripts/WebScriptServlet.java | 68 ++-- ...ava => WebScriptServletAuthenticator.java} | 107 +++--- ...uest.java => WebScriptServletRequest.java} | 72 +++- .../web/scripts/WebScriptServletResponse.java | 95 ++++++ .../web/scripts/WebScriptServletRuntime.java | 128 +++++++ .../web/scripts/WebScriptTransaction.java | 100 ------ .../web/scripts/bean/SearchProxy.java | 9 +- .../WebClientPortletAuthenticator.java | 158 +++++++++ .../web/scripts/portlet/WebScriptPortlet.java | 287 ++++++++++++++++ .../WebScriptPortletAuthenticator.java | 51 +++ .../portlet/WebScriptPortletRequest.java | 265 +++++++++++++++ .../portlet/WebScriptPortletResponse.java | 109 ++++++ source/web/WEB-INF/portlet.xml | 64 ++++ source/web/WEB-INF/web.xml | 4 + 31 files changed, 1981 insertions(+), 885 deletions(-) create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/keywordsearch_get_portlet.ftl delete mode 100644 source/java/org/alfresco/web/scripts/BasicAuthenticator.java create mode 100644 source/java/org/alfresco/web/scripts/BasicHttpAuthenticator.java create mode 100644 source/java/org/alfresco/web/scripts/ScriptUrlMethod.java delete mode 100644 source/java/org/alfresco/web/scripts/SystemAuthenticator.java delete mode 100644 source/java/org/alfresco/web/scripts/TrustedAuthenticator.java delete mode 100644 source/java/org/alfresco/web/scripts/WebScriptLogger.java create mode 100644 source/java/org/alfresco/web/scripts/WebScriptRuntime.java rename source/java/org/alfresco/web/scripts/{WebScriptResponse.java => WebScriptServletAuthenticator.java} (65%) rename source/java/org/alfresco/web/scripts/{WebScriptRequest.java => WebScriptServletRequest.java} (66%) create mode 100644 source/java/org/alfresco/web/scripts/WebScriptServletResponse.java create mode 100644 source/java/org/alfresco/web/scripts/WebScriptServletRuntime.java delete mode 100644 source/java/org/alfresco/web/scripts/WebScriptTransaction.java create mode 100644 source/java/org/alfresco/web/scripts/portlet/WebClientPortletAuthenticator.java create mode 100644 source/java/org/alfresco/web/scripts/portlet/WebScriptPortlet.java create mode 100644 source/java/org/alfresco/web/scripts/portlet/WebScriptPortletAuthenticator.java create mode 100644 source/java/org/alfresco/web/scripts/portlet/WebScriptPortletRequest.java create mode 100644 source/java/org/alfresco/web/scripts/portlet/WebScriptPortletResponse.java diff --git a/config/alfresco/templates/webscripts/org/alfresco/portlets/doclist_get_html.ftl b/config/alfresco/templates/webscripts/org/alfresco/portlets/doclist_get_html.ftl index 3d81bf10e3..02204faf1e 100644 --- a/config/alfresco/templates/webscripts/org/alfresco/portlets/doclist_get_html.ftl +++ b/config/alfresco/templates/webscripts/org/alfresco/portlets/doclist_get_html.ftl @@ -41,11 +41,11 @@ - - - - - + + + + +
All ItemsWord DocumentsHTML DocumentsPDF DocumentsRecently ModifiedAll ItemsWord DocumentsHTML DocumentsPDF DocumentsRecently Modified
diff --git a/config/alfresco/templates/webscripts/org/alfresco/portlets/mytasks_get_html.ftl b/config/alfresco/templates/webscripts/org/alfresco/portlets/mytasks_get_html.ftl index c8d293cfeb..b9186516b5 100644 --- a/config/alfresco/templates/webscripts/org/alfresco/portlets/mytasks_get_html.ftl +++ b/config/alfresco/templates/webscripts/org/alfresco/portlets/mytasks_get_html.ftl @@ -27,11 +27,11 @@ - - - - - + + + + +
Tasks to doDue TodayNext 7 daysNo due dateOverdueTasks to doDue TodayNext 7 daysNo due dateOverdue
@@ -94,7 +94,7 @@ <#list t.transitions as wt> - +
${wt.label?html}${wt.label?html}
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/keywordsearch_get_desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/keywordsearch_get_desc.xml index 58ca751178..ce4145e5c2 100644 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/keywordsearch_get_desc.xml +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/keywordsearch_get_desc.xml @@ -4,5 +4,6 @@ + guest \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/keywordsearch_get_portlet.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/keywordsearch_get_portlet.ftl new file mode 100644 index 0000000000..259e749fc5 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/keywordsearch_get_portlet.ftl @@ -0,0 +1,33 @@ + + + + +
Results ${search.startIndex} - ${search.startIndex + search.totalPageItems - 1} of ${search.totalResults} for ${search.searchTerms} visible to user <#if person??>${person.properties.userName}<#else>unknown.
+
+ +<#list search.results as row> + + + + <#if row.properties.description?? == true> + + + + + + +
${row.name}
${row.properties.description}
+
+ + + +<#if search.startPage > 1> + + + +<#if search.startPage < search.totalPages> + + + + +
firstprevious${search.startPage}nextlast
\ No newline at end of file diff --git a/config/alfresco/web-scripts-application-context-test.xml b/config/alfresco/web-scripts-application-context-test.xml index 57751164d7..7cf91a882e 100644 --- a/config/alfresco/web-scripts-application-context-test.xml +++ b/config/alfresco/web-scripts-application-context-test.xml @@ -8,11 +8,7 @@ - - - - - + diff --git a/config/alfresco/web-scripts-application-context.xml b/config/alfresco/web-scripts-application-context.xml index 9b0cf6811e..d4f1cdab88 100644 --- a/config/alfresco/web-scripts-application-context.xml +++ b/config/alfresco/web-scripts-application-context.xml @@ -63,36 +63,24 @@ - - - webscript_default - - - - - - + + + + + + - - + + + - - - - - - - - - - @@ -119,6 +107,7 @@ application/json application/opensearchdescription+xml text/plain + text/html diff --git a/source/java/org/alfresco/web/scripts/AbstractWebScript.java b/source/java/org/alfresco/web/scripts/AbstractWebScript.java index 0ef031dc9c..a2e1c507e6 100644 --- a/source/java/org/alfresco/web/scripts/AbstractWebScript.java +++ b/source/java/org/alfresco/web/scripts/AbstractWebScript.java @@ -26,7 +26,6 @@ package org.alfresco.web.scripts; import java.io.Writer; import java.util.Date; -import java.util.Enumeration; import java.util.HashMap; import java.util.Map; @@ -36,7 +35,6 @@ import org.alfresco.repo.template.AbsoluteUrlMethod; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.ScriptLocation; -import org.alfresco.service.cmr.repository.TemplateImageResolver; import org.alfresco.service.cmr.repository.TemplateService; import org.alfresco.service.descriptor.DescriptorService; import org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication; @@ -174,10 +172,9 @@ public abstract class AbstractWebScript implements WebScript final protected Map createArgModel(WebScriptRequest req) { Map args = new ScriptableHashMap(); - Enumeration names = req.getParameterNames(); - while (names.hasMoreElements()) + String[] names = req.getParameterNames(); + for (String name : names) { - String name = (String)names.nextElement(); args.put(name, req.getParameter(name)); } return args; @@ -269,6 +266,7 @@ public abstract class AbstractWebScript implements WebScript // add template support model.put("absurl", new AbsoluteUrlMethod(req.getServerPath())); + model.put("scripturl", new ScriptUrlMethod(req, res)); model.put("date", new Date()); model.put(TemplateService.KEY_IMAGE_RESOLVER, getWebScriptRegistry().getTemplateImageResolver()); diff --git a/source/java/org/alfresco/web/scripts/BasicAuthenticator.java b/source/java/org/alfresco/web/scripts/BasicAuthenticator.java deleted file mode 100644 index a4e5160524..0000000000 --- a/source/java/org/alfresco/web/scripts/BasicAuthenticator.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * 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; - -import org.alfresco.repo.security.authentication.AuthenticationException; -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.service.cmr.security.AuthenticationService; -import org.alfresco.util.Base64; -import org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication; -import org.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - - -/** - * HTTP Basic Authentication Interceptor - * - * @author davidc - */ -public class BasicAuthenticator implements MethodInterceptor -{ - // Logger - private static final Log logger = LogFactory.getLog(BasicAuthenticator.class); - - // dependencies - private AuthenticationService authenticationService; - - /** - * @param authenticationService - */ - public void setAuthenticationService(AuthenticationService authenticationService) - { - this.authenticationService = authenticationService; - } - - /* (non-Javadoc) - * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation) - */ - public Object invoke(MethodInvocation invocation) - throws Throwable - { - boolean authorized = false; - String currentUser = null; - Object retVal = null; - Object[] args = invocation.getArguments(); - WebScriptRequest request = (WebScriptRequest)args[0]; - WebScript service = (WebScript)invocation.getThis(); - WebScriptDescription description = service.getDescription(); - - try - { - // - // Determine if user already authenticated - // - - currentUser = AuthenticationUtil.getCurrentUserName(); - if (logger.isDebugEnabled()) - logger.debug("Current authentication: " + (currentUser == null ? "unauthenticated" : "authenticated as " + currentUser)); - - // - // validate credentials - // - - boolean isGuest = request.isGuest(); - String authorization = request.getHeader("Authorization"); - - if (logger.isDebugEnabled()) - { - logger.debug("Web Service authentication required: " + description.getRequiredAuthentication()); - logger.debug("Guest login: " + isGuest); - logger.debug("Authorization provided (overrides Guest login): " + (authorization != null && authorization.length() > 0)); - } - - // authenticate as guest, if service allows - if (((authorization == null || authorization.length() == 0) || isGuest) - && description.getRequiredAuthentication().equals(RequiredAuthentication.guest)) - { - if (logger.isDebugEnabled()) - logger.debug("Authenticating as Guest"); - - authenticationService.authenticateAsGuest(); - authorized = true; - } - - // authenticate as specified by HTTP Basic Authentication - else if (authorization != null && authorization.length() > 0) - { - try - { - String[] authorizationParts = authorization.split(" "); - if (!authorizationParts[0].equalsIgnoreCase("basic")) - { - throw new WebScriptException("Authorization '" + authorizationParts[0] + "' not supported."); - } - String decodedAuthorisation = new String(Base64.decode(authorizationParts[1])); - String[] parts = decodedAuthorisation.split(":"); - - if (parts.length == 1) - { - if (logger.isDebugEnabled()) - logger.debug("Authenticating ticket " + parts[0]); - - // assume a ticket has been passed - authenticationService.validate(parts[0]); - authorized = true; - } - else - { - if (logger.isDebugEnabled()) - logger.debug("Authenticating user " + parts[0]); - - // assume username and password passed - if (parts[0].equals(AuthenticationUtil.getGuestUserName())) - { - if (description.getRequiredAuthentication().equals(RequiredAuthentication.guest)) - { - authenticationService.authenticateAsGuest(); - authorized = true; - } - } - else - { - authenticationService.authenticate(parts[0], parts[1].toCharArray()); - authorized = true; - } - } - } - catch(AuthenticationException e) - { - // failed authentication - } - } - - // - // execute web script or request authorization - // - - if (authorized) - { - retVal = invocation.proceed(); - } - else - { - if (logger.isDebugEnabled()) - logger.debug("Requesting authorization credentials"); - - WebScriptResponse response = (WebScriptResponse)args[1]; - response.setStatus(401); - response.setHeader("WWW-Authenticate", "Basic realm=\"Alfresco\""); - } - } - finally - { - // reset authentication - if (authorized) - { - authenticationService.clearCurrentSecurityContext(); - if (currentUser != null) - { - AuthenticationUtil.setCurrentUser(currentUser); - } - - if (logger.isDebugEnabled()) - logger.debug("Authentication reset: " + (currentUser == null ? "unauthenticated" : "authenticated as " + currentUser)); - } - } - - return retVal; - } - -} diff --git a/source/java/org/alfresco/web/scripts/BasicHttpAuthenticator.java b/source/java/org/alfresco/web/scripts/BasicHttpAuthenticator.java new file mode 100644 index 0000000000..9c3fd2252b --- /dev/null +++ b/source/java/org/alfresco/web/scripts/BasicHttpAuthenticator.java @@ -0,0 +1,151 @@ +/* + * 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; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.repo.security.authentication.AuthenticationException; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.util.Base64; +import org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +/** + * HTTP Basic Authentication Interceptor + * + * @author davidc + */ +public class BasicHttpAuthenticator implements WebScriptServletAuthenticator +{ + // Logger + private static final Log logger = LogFactory.getLog(BasicHttpAuthenticator.class); + + // dependencies + private AuthenticationService authenticationService; + + /** + * @param authenticationService + */ + public void setAuthenticationService(AuthenticationService authenticationService) + { + this.authenticationService = authenticationService; + } + + /* (non-Javadoc) + * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation) + */ + public void authenticate(RequiredAuthentication required, boolean isGuest, HttpServletRequest req, HttpServletResponse res) + { + boolean authorized = false; + + // + // validate credentials + // + + String authorization = req.getHeader("Authorization"); + + if (logger.isDebugEnabled()) + { + logger.debug("HTTP Authorization provided: " + (authorization != null && authorization.length() > 0)); + } + + // authenticate as guest, if service allows + if (isGuest) + { + if (logger.isDebugEnabled()) + logger.debug("Authenticating as Guest"); + + authenticationService.authenticateAsGuest(); + authorized = true; + } + + // authenticate as specified by HTTP Basic Authentication + else if (authorization != null && authorization.length() > 0) + { + try + { + String[] authorizationParts = authorization.split(" "); + if (!authorizationParts[0].equalsIgnoreCase("basic")) + { + throw new WebScriptException("Authorization '" + authorizationParts[0] + "' not supported."); + } + String decodedAuthorisation = new String(Base64.decode(authorizationParts[1])); + String[] parts = decodedAuthorisation.split(":"); + + if (parts.length == 1) + { + if (logger.isDebugEnabled()) + logger.debug("Authenticating ticket " + parts[0]); + + // assume a ticket has been passed + authenticationService.validate(parts[0]); + authorized = true; + } + else + { + if (logger.isDebugEnabled()) + logger.debug("Authenticating user " + parts[0]); + + // assume username and password passed + if (parts[0].equals(AuthenticationUtil.getGuestUserName())) + { + if (required == RequiredAuthentication.guest) + { + authenticationService.authenticateAsGuest(); + authorized = true; + } + } + else + { + authenticationService.authenticate(parts[0], parts[1].toCharArray()); + authorized = true; + } + } + } + catch(AuthenticationException e) + { + // failed authentication + } + } + + // + // request credentials if not authorized + // + + if (!authorized) + { + if (logger.isDebugEnabled()) + logger.debug("Requesting authorization credentials"); + + res.setStatus(401); + res.setHeader("WWW-Authenticate", "Basic realm=\"Alfresco\""); + } + } + +} diff --git a/source/java/org/alfresco/web/scripts/DeclarativeWebScriptRegistry.java b/source/java/org/alfresco/web/scripts/DeclarativeWebScriptRegistry.java index 8af3c70abe..5e12de1401 100644 --- a/source/java/org/alfresco/web/scripts/DeclarativeWebScriptRegistry.java +++ b/source/java/org/alfresco/web/scripts/DeclarativeWebScriptRegistry.java @@ -37,23 +37,20 @@ import java.util.TreeMap; import javax.servlet.ServletContext; import org.alfresco.service.cmr.repository.TemplateImageResolver; +import org.alfresco.util.AbstractLifecycleBean; import org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication; import org.alfresco.web.scripts.WebScriptDescription.RequiredTransaction; import org.alfresco.web.scripts.WebScriptDescription.URI; import org.alfresco.web.ui.common.Utils; -import org.aopalliance.intercept.MethodInterceptor; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; -import org.springframework.aop.framework.ProxyFactory; -import org.springframework.aop.support.RegexpMethodPointcutAdvisor; -import org.springframework.beans.BeansException; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ApplicationEvent; import org.springframework.web.context.ServletContextAware; @@ -62,17 +59,14 @@ import org.springframework.web.context.ServletContextAware; * * @author davidc */ -public class DeclarativeWebScriptRegistry implements WebScriptRegistry, ApplicationContextAware, ServletContextAware, InitializingBean +public class DeclarativeWebScriptRegistry extends AbstractLifecycleBean + implements WebScriptRegistry, ServletContextAware, InitializingBean { // Logger private static final Log logger = LogFactory.getLog(DeclarativeWebScriptRegistry.class); - private ApplicationContext applicationContext; private ServletContext servletContext; private String defaultWebScript; - private MethodInterceptor authenticator; - private MethodInterceptor serviceLogger; - private MethodInterceptor serviceTransaction; private FormatRegistry formatRegistry; private WebScriptStorage storage; private TemplateImageResolver imageResolver; @@ -101,36 +95,6 @@ public class DeclarativeWebScriptRegistry implements WebScriptRegistry, Applicat this.storage = storage; } - /** - * Sets the web script authenticator - * - * @param authenticator - */ - public void setAuthenticator(MethodInterceptor authenticator) - { - this.authenticator = authenticator; - } - - /** - * Sets the web script logger - * - * @param serviceLogger - */ - public void setServiceLogger(MethodInterceptor serviceLogger) - { - this.serviceLogger = serviceLogger; - } - - /** - * Sets the service transaction - * - * @param serviceTransaction - */ - public void setServiceTransaction(MethodInterceptor serviceTransaction) - { - this.serviceTransaction = serviceTransaction; - } - /** * Sets the default service implementation bean * @@ -159,14 +123,6 @@ public class DeclarativeWebScriptRegistry implements WebScriptRegistry, Applicat this.servletContext = context; } - /* (non-Javadoc) - * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) - */ - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException - { - this.applicationContext = applicationContext; - } - /* (non-Javadoc) * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() */ @@ -181,6 +137,33 @@ public class DeclarativeWebScriptRegistry implements WebScriptRegistry, Applicat }; } + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRegistry#reset() + */ + public void reset() + { + getTemplateProcessor().resetCache(); + getScriptProcessor().resetCache(); + initWebScripts(); + } + + /* (non-Javadoc) + * @see org.alfresco.util.AbstractLifecycleBean#onBootstrap(org.springframework.context.ApplicationEvent) + */ + @Override + protected void onBootstrap(ApplicationEvent event) + { + initWebScripts(); + } + + /* (non-Javadoc) + * @see org.alfresco.util.AbstractLifecycleBean#onShutdown(org.springframework.context.ApplicationEvent) + */ + @Override + protected void onShutdown(ApplicationEvent event) + { + } + /** * Initialise Web Scripts * @@ -245,56 +228,17 @@ public class DeclarativeWebScriptRegistry implements WebScriptRegistry, Applicat } // construct service implementation + ApplicationContext applicationContext = getApplicationContext(); String serviceImplName = (applicationContext.containsBean("webscript." + id)) ? "webscript." + id : defaultWebScript; AbstractWebScript serviceImpl = (AbstractWebScript)applicationContext.getBean(serviceImplName); serviceImpl.setDescription(serviceDesc); serviceImpl.init(this); - // wrap service implementation in appropriate interceptors (e.g. authentication) - WebScript serviceImplIF = (WebScript)serviceImpl; - if (serviceLogger != null && serviceTransaction != null && authenticator != null) - { - ProxyFactory authFactory = new ProxyFactory(); - authFactory.addInterface(WebScript.class); - authFactory.setTarget(serviceImplIF); - - // logging interceptor - if (serviceLogger != null) - { - RegexpMethodPointcutAdvisor advisor = new RegexpMethodPointcutAdvisor(".*execute", serviceLogger); - authFactory.addAdvisor(advisor); - } - - // transaction interceptor - if (serviceDesc.getRequiredTransaction() != RequiredTransaction.none) - { - if (serviceTransaction == null) - { - throw new WebScriptException("Web Script Transaction not specified"); - } - RegexpMethodPointcutAdvisor advisor = new RegexpMethodPointcutAdvisor(".*execute", serviceTransaction); - authFactory.addAdvisor(advisor); - } - - // authentication interceptor - if (serviceDesc.getRequiredAuthentication() != RequiredAuthentication.none) - { - if (authenticator == null) - { - throw new WebScriptException("Web Script Authenticator not specified"); - } - RegexpMethodPointcutAdvisor advisor = new RegexpMethodPointcutAdvisor(".*execute", authenticator); - authFactory.addAdvisor(advisor); - } - - serviceImplIF = (WebScript)authFactory.getProxy(); - } - if (logger.isDebugEnabled()) logger.debug("Found Web Script " + serviceDescPath + " (id: " + id + ", impl: " + serviceImplName + ", auth: " + serviceDesc.getRequiredAuthentication() + ", trx: " + serviceDesc.getRequiredTransaction() + ")"); // register service and its urls - webscriptsById.put(id, serviceImplIF); + webscriptsById.put(id, serviceImpl); for (URI uri : serviceDesc.getURIs()) { // establish static part of url template @@ -323,7 +267,7 @@ public class DeclarativeWebScriptRegistry implements WebScriptRegistry, Applicat } else { - webscriptsByURL.put(uriIdx, serviceImplIF); + webscriptsByURL.put(uriIdx, serviceImpl); if (logger.isDebugEnabled()) logger.debug("Registered Web Script URL '" + uriIdx + "'"); @@ -476,7 +420,6 @@ public class DeclarativeWebScriptRegistry implements WebScriptRegistry, Applicat } } - /* (non-Javadoc) * @see org.alfresco.web.scripts.WebScriptRegistry#getWebScripts() */ @@ -553,18 +496,7 @@ public class DeclarativeWebScriptRegistry implements WebScriptRegistry, Applicat { return this.storage.getScriptProcessor(); } - - /* (non-Javadoc) - * @see org.alfresco.web.scripts.WebScriptRegistry#reset() - */ - public void reset() - { - getTemplateProcessor().resetCache(); - getScriptProcessor().resetCache(); - initWebScripts(); - } - /** * Web Script Match * diff --git a/source/java/org/alfresco/web/scripts/ScriptUrlMethod.java b/source/java/org/alfresco/web/scripts/ScriptUrlMethod.java new file mode 100644 index 0000000000..82eed62143 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/ScriptUrlMethod.java @@ -0,0 +1,84 @@ +/* + * 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; + +import java.util.List; + +import freemarker.template.TemplateMethodModelEx; +import freemarker.template.TemplateModelException; +import freemarker.template.TemplateScalarModel; + +/** + * @author David Caruana + * + * Custom FreeMarker Template language method. + *

+ * Render script url independent of script hosting environment e.g. render inside / outside + * portal. + *

+ * Usage: scripturl(String url) + */ +public final class ScriptUrlMethod implements TemplateMethodModelEx +{ + WebScriptRequest req; + WebScriptResponse res; + + /** + * Construct + * + * @param basePath base path used to construct absolute url + */ + public ScriptUrlMethod(WebScriptRequest req, WebScriptResponse res) + { + this.req = req; + this.res = res; + } + + + /** + * @see freemarker.template.TemplateMethodModel#exec(java.util.List) + */ + public Object exec(List args) throws TemplateModelException + { + String result = ""; + + if (args.size() == 1) + { + Object arg0 = args.get(0); + if (arg0 instanceof TemplateScalarModel) + { + String arg = ((TemplateScalarModel)arg0).getAsString(); + String url = req.getServicePath(); + url += arg; + url += (arg.length() > 0) ? "&" : ""; + url += "guest=" + (req.isGuest() ? "true" : ""); + url += (req.getFormat().length() > 0) ? "&format=" + req.getFormat() : ""; + result = res.encodeScriptUrl(url); + } + } + + return result; + } +} diff --git a/source/java/org/alfresco/web/scripts/SystemAuthenticator.java b/source/java/org/alfresco/web/scripts/SystemAuthenticator.java deleted file mode 100644 index f59815e43c..0000000000 --- a/source/java/org/alfresco/web/scripts/SystemAuthenticator.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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; - -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - - -/** - * System Authentication Interceptor - * - * @author davidc - */ -public class SystemAuthenticator implements MethodInterceptor -{ - // Logger - private static final Log logger = LogFactory.getLog(SystemAuthenticator.class); - - - /* (non-Javadoc) - * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation) - */ - public Object invoke(MethodInvocation invocation) - throws Throwable - { - String currentUser = null; - Object retVal = null; - - try - { - // - // Determine if user already authenticated - // - - currentUser = AuthenticationUtil.getCurrentUserName(); - if (logger.isDebugEnabled()) - logger.debug("Current authentication: " + (currentUser == null ? "unauthenticated" : "authenticated as " + currentUser)); - - // - // Force system user - // - - if (logger.isDebugEnabled()) - logger.debug("Authenticating as System"); - - AuthenticationUtil.setSystemUserAsCurrentUser(); - - // - // Invoke service - // - - retVal = invocation.proceed(); - } - finally - { - AuthenticationUtil.clearCurrentSecurityContext(); - if (currentUser != null) - { - AuthenticationUtil.setCurrentUser(currentUser); - } - - if (logger.isDebugEnabled()) - logger.debug("Authentication reset: " + (currentUser == null ? "unauthenticated" : "authenticated as " + currentUser)); - } - - return retVal; - } - -} diff --git a/source/java/org/alfresco/web/scripts/TestWebScriptServer.java b/source/java/org/alfresco/web/scripts/TestWebScriptServer.java index 08e226b0b5..fbe320babc 100644 --- a/source/java/org/alfresco/web/scripts/TestWebScriptServer.java +++ b/source/java/org/alfresco/web/scripts/TestWebScriptServer.java @@ -88,6 +88,7 @@ public class TestWebScriptServer this.registry = registry; } + /** * Sets the Messages resource bundle * @@ -162,15 +163,9 @@ public class TestWebScriptServer MockHttpServletRequest req = createRequest("get", uri); MockHttpServletResponse res = new MockHttpServletResponse(); - WebScriptMatch match = registry.findWebScript(req.getMethod(), uri); - if (match == null) - { - throw new WebScriptException("No service bound to uri '" + uri + "'"); - } - - WebScriptRequest apiReq = new WebScriptRequest(req, match); - WebScriptResponse apiRes = new WebScriptResponse(res); - match.getWebScript().execute(apiReq, apiRes); + WebScriptRuntime runtime = new WebScriptServletRuntime(registry, transactionService, null, req, res); + runtime.executeScript(); + return res; } @@ -346,5 +341,5 @@ public class TestWebScriptServer return req; } - + } diff --git a/source/java/org/alfresco/web/scripts/TrustedAuthenticator.java b/source/java/org/alfresco/web/scripts/TrustedAuthenticator.java deleted file mode 100644 index e6890a9d4d..0000000000 --- a/source/java/org/alfresco/web/scripts/TrustedAuthenticator.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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; - -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - - -/** - * Trusted Authentication Interceptor - * - * Just use the currently authenticated user - * - * @author davidc - */ -public class TrustedAuthenticator implements MethodInterceptor -{ - // Logger - private static final Log logger = LogFactory.getLog(TrustedAuthenticator.class); - - - /* (non-Javadoc) - * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation) - */ - public Object invoke(MethodInvocation invocation) - throws Throwable - { - String currentUser = null; - Object retVal = null; - - try - { - // - // Determine if user already authenticated - // - - currentUser = AuthenticationUtil.getCurrentUserName(); - if (logger.isDebugEnabled()) - logger.debug("Current authentication: " + (currentUser == null ? "unauthenticated" : "authenticated as " + currentUser)); - - // - // Use current authentication - // - - // - // Invoke service - // - - retVal = invocation.proceed(); - } - finally - { - AuthenticationUtil.clearCurrentSecurityContext(); - if (currentUser != null) - { - AuthenticationUtil.setCurrentUser(currentUser); - } - - if (logger.isDebugEnabled()) - logger.debug("Authentication reset: " + (currentUser == null ? "unauthenticated" : "authenticated as " + currentUser)); - } - - return retVal; - } - -} diff --git a/source/java/org/alfresco/web/scripts/WebClientAuthenticator.java b/source/java/org/alfresco/web/scripts/WebClientAuthenticator.java index b4db1db94b..3f7e6f1133 100644 --- a/source/java/org/alfresco/web/scripts/WebClientAuthenticator.java +++ b/source/java/org/alfresco/web/scripts/WebClientAuthenticator.java @@ -24,16 +24,16 @@ */ package org.alfresco.web.scripts; -import javax.servlet.ServletContext; +import java.io.IOException; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.web.app.servlet.AuthenticationHelper; import org.alfresco.web.app.servlet.AuthenticationStatus; import org.alfresco.web.app.servlet.BaseServlet; import org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication; -import org.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.web.context.ServletContextAware; @@ -44,14 +44,13 @@ import org.springframework.web.context.ServletContextAware; * * @author davidc */ -public class WebClientAuthenticator implements MethodInterceptor, ServletContextAware +public class WebClientAuthenticator implements WebScriptServletAuthenticator, ServletContextAware { // Logger private static final Log logger = LogFactory.getLog(WebClientAuthenticator.class); // dependencies private ServletContext context; - private AuthenticationService authenticationService; /* (non-Javadoc) @@ -62,112 +61,69 @@ public class WebClientAuthenticator implements MethodInterceptor, ServletContext this.context = context; } - /** - * @param authenticationService - */ - public void setAuthenticationService(AuthenticationService authenticationService) - { - this.authenticationService = authenticationService; - } - /* (non-Javadoc) - * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation) + * @see org.alfresco.web.scripts.WebScriptServletAuthenticator#authenticate(org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication, boolean, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ - public Object invoke(MethodInvocation invocation) - throws Throwable + public void authenticate(RequiredAuthentication required, boolean isGuest, HttpServletRequest req, HttpServletResponse res) { - String currentUser = null; - Object retVal = null; - Object[] args = invocation.getArguments(); - WebScriptRequest request = (WebScriptRequest)args[0]; - WebScriptResponse response = (WebScriptResponse)args[1]; - WebScript service = (WebScript)invocation.getThis(); - WebScriptDescription description = service.getDescription(); AuthenticationStatus status = null; try { - // - // Determine if user already authenticated - // - - currentUser = AuthenticationUtil.getCurrentUserName(); - if (logger.isDebugEnabled()) - logger.debug("Current authentication: " + (currentUser == null ? "unauthenticated" : "authenticated as " + currentUser)); - // // validate credentials // - String ticket = request.getParameter("ticket"); - boolean isGuest = request.isGuest(); + String ticket = req.getParameter("ticket"); if (logger.isDebugEnabled()) { - logger.debug("Web Script authentication required: " + description.getRequiredAuthentication()); - logger.debug("Guest login: " + isGuest); - logger.debug("Ticket provided: " + (ticket != null && ticket.length() > 0)); + logger.debug("Alfresco ticket provided: " + (ticket != null && ticket.length() > 0)); } if (ticket != null && ticket.length() > 0) { if (logger.isDebugEnabled()) logger.debug("Authenticating ticket " + ticket); - - status = AuthenticationHelper.authenticate(context, request, response, ticket); + + status = AuthenticationHelper.authenticate(context, req, res, ticket); } else { - if (isGuest && description.getRequiredAuthentication() == RequiredAuthentication.guest) + if (isGuest) { if (logger.isDebugEnabled()) logger.debug("Authenticating as Guest"); - - status = AuthenticationHelper.authenticate(context, request, response, true); + + status = AuthenticationHelper.authenticate(context, req, res, true); } else { if (logger.isDebugEnabled()) logger.debug("Authenticating session"); - - status = AuthenticationHelper.authenticate(context, request, response, false); + + status = AuthenticationHelper.authenticate(context, req, res, false); } } - + // - // execute web script or request authorization + // if not authorized, redirect to login page // - if (status != null && status != AuthenticationStatus.Failure) - { - retVal = invocation.proceed(); - } - else + if (status == null || status == AuthenticationStatus.Failure) { // authentication failed - now need to display the login page to the user, if asked to if (logger.isDebugEnabled()) logger.debug("Redirecting to Alfresco Login"); - - BaseServlet.redirectToLoginPage(request, response, context); + + BaseServlet.redirectToLoginPage(req, res, context); } } - finally + catch(IOException e) { - if (status != null && status != AuthenticationStatus.Failure) - { - authenticationService.clearCurrentSecurityContext(); - if (currentUser != null) - { - AuthenticationUtil.setCurrentUser(currentUser); - } - - if (logger.isDebugEnabled()) - logger.debug("Authentication reset: " + (currentUser == null ? "unauthenticated" : "authenticated as " + currentUser)); - } + throw new WebScriptException("Failed to authenticate", e); } - - return retVal; } } diff --git a/source/java/org/alfresco/web/scripts/WebScriptLogger.java b/source/java/org/alfresco/web/scripts/WebScriptLogger.java deleted file mode 100644 index 46b2e05a51..0000000000 --- a/source/java/org/alfresco/web/scripts/WebScriptLogger.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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; - -import org.alfresco.i18n.I18NUtil; -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - - -/** - * Web Script Logger - * - * @author davidc - */ -public class WebScriptLogger implements MethodInterceptor -{ - // Logger - private static final Log logger = LogFactory.getLog(WebScriptLogger.class); - - /* (non-Javadoc) - * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation) - */ - public Object invoke(MethodInvocation invocation) - throws Throwable - { - Object retVal = null; - - if (logger.isDebugEnabled()) - { - WebScript service = (WebScript)invocation.getThis(); - WebScriptDescription description = service.getDescription(); - String user = AuthenticationUtil.getCurrentUserName(); - String locale = I18NUtil.getLocale().toString(); - logger.debug("Invoking Web Script " + description.getId() + (user == null ? " (unauthenticated)" : " (authenticated as " + user + ")" + " (" + locale + ")")); - long start = System.currentTimeMillis(); - retVal = invocation.proceed(); - long end = System.currentTimeMillis(); - logger.debug("Web Script " + description.getId() + " executed in " + (end - start) + "ms"); - } - else - { - retVal = invocation.proceed(); - } - - return retVal; - } - -} diff --git a/source/java/org/alfresco/web/scripts/WebScriptRuntime.java b/source/java/org/alfresco/web/scripts/WebScriptRuntime.java new file mode 100644 index 0000000000..d256338aca --- /dev/null +++ b/source/java/org/alfresco/web/scripts/WebScriptRuntime.java @@ -0,0 +1,318 @@ +/* + * 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; + +import java.io.IOException; + +import org.alfresco.i18n.I18NUtil; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.transaction.TransactionUtil; +import org.alfresco.service.transaction.TransactionService; +import org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication; +import org.alfresco.web.scripts.WebScriptDescription.RequiredTransaction; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +/** + * Encapsulates the execution of a single Web Script. + * + * Provides support for logging, transactions and authentication. + * + * Sub-classes of WebScriptRuntime maintain the execution environment e.g. servlet + * request & response. + * + * A new instance of WebScriptRuntime is required for each new execution environment. + * + * @author davidc + */ +public abstract class WebScriptRuntime +{ + // Logger + protected static final Log logger = LogFactory.getLog(WebScriptRuntime.class); + + /** Component Dependencies */ + private WebScriptRegistry registry; + private TransactionService transactionService; + + /** + * Construct + * + * @param registry web script registry + * @param transactionService transaction service + */ + public WebScriptRuntime(WebScriptRegistry registry, TransactionService transactionService) + { + this.registry = registry; + this.transactionService = transactionService; + } + + /** + * Execute the Web Script encapsulated by this Web Script Runtime + */ + public void executeScript() + { + long startRuntime = System.currentTimeMillis(); + + String method = getScriptMethod(); + String scriptUrl = getScriptUrl(); + + try + { + if (logger.isDebugEnabled()) + logger.debug("Processing script url (" + method + ") " + scriptUrl); + + WebScriptMatch match = registry.findWebScript(method, scriptUrl); + if (match != null) + { + // setup web script context + final WebScriptRequest scriptReq = createRequest(match); + final WebScriptResponse scriptRes = createResponse(); + + if (logger.isDebugEnabled()) + logger.debug("Agent: " + scriptReq.getAgent()); + + long startScript = System.currentTimeMillis(); + final WebScript script = match.getWebScript(); + final WebScriptDescription description = script.getDescription(); + + try + { + if (logger.isDebugEnabled()) + { + String user = AuthenticationUtil.getCurrentUserName(); + String locale = I18NUtil.getLocale().toString(); + logger.debug("Invoking Web Script " + description.getId() + (user == null ? " (unauthenticated)" : " (authenticated as " + user + ")" + " (" + locale + ")")); + } + + if (description.getRequiredTransaction() == RequiredTransaction.none) + { + authenticatedExecute(scriptReq, scriptRes); + } + else + { + // encapsulate script within transaction + TransactionUtil.TransactionWork work = new TransactionUtil.TransactionWork() + { + public Object doWork() throws Throwable + { + if (logger.isDebugEnabled()) + logger.debug("Begin transaction: " + description.getRequiredTransaction()); + + authenticatedExecute(scriptReq, scriptRes); + + if (logger.isDebugEnabled()) + logger.debug("End transaction: " + description.getRequiredTransaction()); + + return null; + } + }; + + if (description.getRequiredTransaction() == RequiredTransaction.required) + { + TransactionUtil.executeInUserTransaction(transactionService, work); + } + else + { + TransactionUtil.executeInNonPropagatingUserTransaction(transactionService, work); + } + } + } + catch(IOException e) + { + throw new WebScriptException("Failed to execute script", e); + } + finally + { + if (logger.isDebugEnabled()) + { + long endScript = System.currentTimeMillis(); + logger.debug("Web Script " + description.getId() + " executed in " + (endScript - startScript) + "ms"); + } + } + } + else + { + String msg = "Script url (" + method + ") " + scriptUrl + " does not map to a Web Script."; + if (logger.isDebugEnabled()) + logger.debug(msg); + + throw new WebScriptException(msg); + } + } + finally + { + long endRuntime = System.currentTimeMillis(); + if (logger.isDebugEnabled()) + logger.debug("Processed script url (" + method + ") " + scriptUrl + " in " + (endRuntime - startRuntime) + "ms"); + } + } + + /** + * Execute script whilst authenticated + * + * @param scriptReq Web Script Request + * @param scriptRes Web Script Response + * @throws IOException + */ + protected void authenticatedExecute(WebScriptRequest scriptReq, WebScriptResponse scriptRes) + throws IOException + { + WebScript script = scriptReq.getServiceMatch().getWebScript(); + WebScriptDescription desc = script.getDescription(); + RequiredAuthentication required = desc.getRequiredAuthentication(); + boolean isGuest = scriptReq.isGuest(); + + if (required == RequiredAuthentication.none) + { + wrappedExecute(scriptReq, scriptRes); + } + else if (required == RequiredAuthentication.user && isGuest) + { + throw new WebScriptException("Web Script " + desc.getId() + " requires user authentication; however, a guest has attempted access."); + } + else + { + String currentUser = null; + + try + { + // + // Determine if user already authenticated + // + + currentUser = AuthenticationUtil.getCurrentUserName(); + if (logger.isDebugEnabled()) + { + logger.debug("Current authentication: " + (currentUser == null ? "unauthenticated" : "authenticated as " + currentUser)); + logger.debug("Authentication required: " + required); + logger.debug("Guest login: " + isGuest); + } + + // + // Apply appropriate authentication to Web Script invocation + // + + authenticate(required, isGuest); + + // + // Execute Web Script + wrappedExecute(scriptReq, scriptRes); + } + finally + { + // + // Reset authentication for current thread + // + + AuthenticationUtil.clearCurrentSecurityContext(); + if (currentUser != null) + { + AuthenticationUtil.setCurrentUser(currentUser); + } + + if (logger.isDebugEnabled()) + logger.debug("Authentication reset: " + (currentUser == null ? "unauthenticated" : "authenticated as " + currentUser)); + } + } + } + + /** + * Execute Web Script with pre & post hooks + * + * @param scriptReq Web Script Request + * @param scriptRes Web Script Response + * @throws IOException + */ + protected void wrappedExecute(WebScriptRequest scriptReq, WebScriptResponse scriptRes) + throws IOException + { + boolean execute = preExecute(scriptReq, scriptRes); + if (execute) + { + WebScript script = scriptReq.getServiceMatch().getWebScript(); + script.execute(scriptReq, scriptRes); + postExecute(scriptReq, scriptRes); + } + } + + + /** + * Get the Web Script Method e.g. get, post + * + * @return web script method + */ + protected abstract String getScriptMethod(); + + /** + * Get the Web Script Url + * + * @return web script url + */ + protected abstract String getScriptUrl(); + + /** + * Create a Web Script Request + * + * @param match web script matching the script method and url + * @return web script request + */ + protected abstract WebScriptRequest createRequest(WebScriptMatch match); + + /** + * Create a Web Script Response + * + * @return web script response + */ + protected abstract WebScriptResponse createResponse(); + + /** + * Authenticate Web Script execution + * + * @param required required level of authentication + * @param isGuest is the request accessed as Guest + */ + protected abstract void authenticate(RequiredAuthentication required, boolean isGuest); + + /** + * Pre-execution hook + * + * @param scriptReq Web Script Request + * @param scriptRes Web Script Response + * @return true => execute script, false => do not execute script + */ + protected abstract boolean preExecute(WebScriptRequest scriptReq, WebScriptResponse scriptRes); + + /** + * Post-execution hook + * + * Note: this hook is not invoked if the script is not executed. + * + * @param scriptReq Web Script Request + * @param scriptRes Web Script Response + */ + protected abstract void postExecute(WebScriptRequest scriptReq, WebScriptResponse scriptRes); + +} diff --git a/source/java/org/alfresco/web/scripts/WebScriptServlet.java b/source/java/org/alfresco/web/scripts/WebScriptServlet.java index 9f79609830..568f5ad1ef 100644 --- a/source/java/org/alfresco/web/scripts/WebScriptServlet.java +++ b/source/java/org/alfresco/web/scripts/WebScriptServlet.java @@ -31,6 +31,7 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.alfresco.service.transaction.TransactionService; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.context.ApplicationContext; @@ -49,8 +50,11 @@ public class WebScriptServlet extends HttpServlet // Logger private static final Log logger = LogFactory.getLog(WebScriptServlet.class); - // Web Scripts + // Component Dependencies private DeclarativeWebScriptRegistry registry; + private TransactionService transactionService; + private WebScriptServletAuthenticator authenticator; + @Override @@ -59,14 +63,23 @@ public class WebScriptServlet extends HttpServlet super.init(); ApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext()); registry = (DeclarativeWebScriptRegistry)context.getBean("webscripts.registry"); - registry.initWebScripts(); + transactionService = (TransactionService)context.getBean("transactionComponent"); + + // retrieve authenticator via servlet initialisation parameter + String authenticatorId = getInitParameter("authenticator"); + if (authenticatorId == null || authenticatorId.length() == 0) + { + authenticatorId = "webscripts.authenticator.webclient"; + } + Object bean = context.getBean(authenticatorId); + if (bean == null || !(bean instanceof WebScriptServletAuthenticator)) + { + throw new ServletException("Initialisation parameter 'authenticator' does not refer to a Web Script authenticator (" + authenticatorId + ")"); + } + authenticator = (WebScriptServletAuthenticator)bean; } -// TODO: -// - authentication (as suggested in http://www.xml.com/pub/a/2003/12/17/dive.html) - - /* * (non-Javadoc) * @@ -75,48 +88,17 @@ public class WebScriptServlet extends HttpServlet */ protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { - long start = System.currentTimeMillis(); + if (logger.isDebugEnabled()) + logger.debug("Processing request (" + req.getMethod() + ") " + req.getRequestURL() + (req.getQueryString() != null ? "?" + req.getQueryString() : "")); try { - // - // Execute appropriate web scripy - // - // TODO: Handle errors (with appropriate HTTP error responses) - - String uri = req.getPathInfo(); - - if (logger.isDebugEnabled()) - logger.debug("Processing request (" + req.getMethod() + ") " + req.getRequestURL() + (req.getQueryString() != null ? "?" + req.getQueryString() : "")); - - WebScriptMatch match = registry.findWebScript(req.getMethod(), uri); - if (match != null) - { - // setup web script context - WebScriptRequest apiReq = new WebScriptRequest(req, match); - WebScriptResponse apiRes = new WebScriptResponse(res); - - if (logger.isDebugEnabled()) - logger.debug("Agent: " + apiReq.getAgent()); - - // execute service - match.getWebScript().execute(apiReq, apiRes); - } - else - { - if (logger.isDebugEnabled()) - logger.debug("Request does not map to service."); - - res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - // TODO: add appropriate error detail - } + WebScriptRuntime runtime = new WebScriptServletRuntime(registry, transactionService, authenticator, req, res); + runtime.executeScript(); } - // TODO: exception handling - finally + catch(Throwable e) { - long end = System.currentTimeMillis(); - if (logger.isDebugEnabled()) - logger.debug("Processed request (" + req.getMethod() + ") " + req.getRequestURL() + (req.getQueryString() != null ? "?" + req.getQueryString() : "") + " in " + (end - start) + "ms"); + res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } } diff --git a/source/java/org/alfresco/web/scripts/WebScriptResponse.java b/source/java/org/alfresco/web/scripts/WebScriptServletAuthenticator.java similarity index 65% rename from source/java/org/alfresco/web/scripts/WebScriptResponse.java rename to source/java/org/alfresco/web/scripts/WebScriptServletAuthenticator.java index 7866c05488..fbf932eb73 100644 --- a/source/java/org/alfresco/web/scripts/WebScriptResponse.java +++ b/source/java/org/alfresco/web/scripts/WebScriptServletAuthenticator.java @@ -1,56 +1,51 @@ -/* - * 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; - -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; - -/** - * API Service Response - * - * @author davidc - */ -public class WebScriptResponse extends HttpServletResponseWrapper -{ - // API Formats - public static final String HTML_FORMAT = "html"; - public static final String ATOM_FORMAT = "atom"; - public static final String RSS_FORMAT = "rss"; - public static final String XML_FORMAT = "xml"; - public static final String JSON_FORMAT = "json"; - public static final String OPENSEARCH_DESCRIPTION_FORMAT = "opensearchdescription"; - - - /** - * Construct - * - * @param res - */ - WebScriptResponse(HttpServletResponse res) - { - super(res); - } - -} +/* + * 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; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication; + + +/** + * Web Script Authenticator for the HTTP Servlet environment + * + * @author davidc + */ +public interface WebScriptServletAuthenticator +{ + + /** + * Authenticate Web Script execution + * + * @param required required level of authentication + * @param isGuest is Guest accessing the web script + * @param req http servlet request + * @param res http servlet response + */ + public void authenticate(RequiredAuthentication required, boolean isGuest, HttpServletRequest req, HttpServletResponse res); + +} diff --git a/source/java/org/alfresco/web/scripts/WebScriptRequest.java b/source/java/org/alfresco/web/scripts/WebScriptServletRequest.java similarity index 66% rename from source/java/org/alfresco/web/scripts/WebScriptRequest.java rename to source/java/org/alfresco/web/scripts/WebScriptServletRequest.java index e85278a0c1..c702a5bb53 100644 --- a/source/java/org/alfresco/web/scripts/WebScriptRequest.java +++ b/source/java/org/alfresco/web/scripts/WebScriptServletRequest.java @@ -24,17 +24,21 @@ */ package org.alfresco.web.scripts; +import java.util.Set; + import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; /** - * Web Script Request + * HTTP Servlet Web Script Request * * @author davidc */ -public class WebScriptRequest extends HttpServletRequestWrapper +public class WebScriptServletRequest implements WebScriptRequest { + /** HTTP Request */ + private HttpServletRequest req; + /** Service bound to this request */ private WebScriptMatch serviceMatch; @@ -45,12 +49,22 @@ public class WebScriptRequest extends HttpServletRequestWrapper * @param req * @param serviceMatch */ - WebScriptRequest(HttpServletRequest req, WebScriptMatch serviceMatch) + WebScriptServletRequest(HttpServletRequest req, WebScriptMatch serviceMatch) { - super(req); + this.req = req; this.serviceMatch = serviceMatch; } + /** + * Gets the HTTP Servlet Request + * + * @return HTTP Servlet Request + */ + public HttpServletRequest getHttpServletRequest() + { + return req; + } + /** * Gets the matching API Service for this request * @@ -70,7 +84,15 @@ public class WebScriptRequest extends HttpServletRequestWrapper */ public String getServerPath() { - return getScheme() + "://" + getServerName() + ":" + getServerPort(); + return req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort(); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getContextPath() + */ + public String getContextPath() + { + return req.getContextPath(); } /** @@ -80,7 +102,7 @@ public class WebScriptRequest extends HttpServletRequestWrapper */ public String getServiceContextPath() { - return getContextPath() + getServletPath(); + return req.getContextPath() + req.getServletPath(); } /** @@ -90,7 +112,7 @@ public class WebScriptRequest extends HttpServletRequestWrapper */ public String getServicePath() { - return getServiceContextPath() + getPathInfo(); + return getServiceContextPath() + req.getPathInfo(); } /** @@ -100,7 +122,34 @@ public class WebScriptRequest extends HttpServletRequestWrapper */ public String getURL() { - return getServicePath() + (getQueryString() != null ? "?" + getQueryString() : ""); + return getServicePath() + (req.getQueryString() != null ? "?" + req.getQueryString() : ""); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getQueryString() + */ + public String getQueryString() + { + return req.getQueryString(); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getParameterNames() + */ + public String[] getParameterNames() + { + Set keys = req.getParameterMap().keySet(); + String[] names = new String[keys.size()]; + keys.toArray(names); + return names; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getParameter(java.lang.String) + */ + public String getParameter(String name) + { + return req.getParameter(name); } /** @@ -117,7 +166,7 @@ public class WebScriptRequest extends HttpServletRequestWrapper public String getExtensionPath() { String servicePath = serviceMatch.getPath(); - String extensionPath = getPathInfo(); + String extensionPath = req.getPathInfo(); int extIdx = extensionPath.indexOf(servicePath); if (extIdx != -1) { @@ -157,7 +206,7 @@ public class WebScriptRequest extends HttpServletRequestWrapper */ public String getAgent() { - String userAgent = getHeader("user-agent"); + String userAgent = req.getHeader("user-agent"); if (userAgent != null) { if (userAgent.indexOf("Firefox/") != -1) @@ -171,4 +220,5 @@ public class WebScriptRequest extends HttpServletRequestWrapper } return null; } + } diff --git a/source/java/org/alfresco/web/scripts/WebScriptServletResponse.java b/source/java/org/alfresco/web/scripts/WebScriptServletResponse.java new file mode 100644 index 0000000000..c0469dfdeb --- /dev/null +++ b/source/java/org/alfresco/web/scripts/WebScriptServletResponse.java @@ -0,0 +1,95 @@ +/* + * 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; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.Writer; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * HTTP Servlet Web Script Response + * + * @author davidc + */ +public class WebScriptServletResponse implements WebScriptResponse +{ + private HttpServletResponse res; + + /** + * Construct + * + * @param res + */ + WebScriptServletResponse(HttpServletResponse res) + { + this.res = res; + } + + /** + * Gets the HTTP Servlet Response + * + * @return HTTP Servlet Response + */ + public HttpServletResponse getHttpServletResponse() + { + return res; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptResponse#setContentType(java.lang.String) + */ + public void setContentType(String contentType) + { + res.setContentType(contentType); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptResponse#getWriter() + */ + public Writer getWriter() throws IOException + { + return res.getWriter(); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptResponse#getOutputStream() + */ + public OutputStream getOutputStream() throws IOException + { + return res.getOutputStream(); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptResponse#encodeScriptUrl(java.lang.String) + */ + public String encodeScriptUrl(String url) + { + return url; + } + +} diff --git a/source/java/org/alfresco/web/scripts/WebScriptServletRuntime.java b/source/java/org/alfresco/web/scripts/WebScriptServletRuntime.java new file mode 100644 index 0000000000..c491978cfd --- /dev/null +++ b/source/java/org/alfresco/web/scripts/WebScriptServletRuntime.java @@ -0,0 +1,128 @@ +/* + * 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; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.service.transaction.TransactionService; +import org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication; + + +/** + * HTTP Servlet Web Script Runtime + * + * @author davidc + */ +public class WebScriptServletRuntime extends WebScriptRuntime +{ + private HttpServletRequest req; + private HttpServletResponse res; + private WebScriptServletAuthenticator authenticator; + + + /** + * Construct + * + * @param registry + * @param transactionService + * @param authenticator + * @param req + * @param res + */ + public WebScriptServletRuntime(WebScriptRegistry registry, TransactionService transactionService, WebScriptServletAuthenticator authenticator, HttpServletRequest req, HttpServletResponse res) + { + super(registry, transactionService); + this.req = req; + this.res = res; + this.authenticator = authenticator; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRuntime#getScriptMethod() + */ + @Override + protected String getScriptMethod() + { + return req.getMethod(); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRuntime#getScriptUrl() + */ + @Override + protected String getScriptUrl() + { + return req.getPathInfo(); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRuntime#createRequest(org.alfresco.web.scripts.WebScriptMatch) + */ + @Override + protected WebScriptRequest createRequest(WebScriptMatch match) + { + return new WebScriptServletRequest(req, match); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRuntime#createResponse() + */ + @Override + protected WebScriptResponse createResponse() + { + return new WebScriptServletResponse(res); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRuntime#authenticate(org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication, boolean) + */ + @Override + protected void authenticate(RequiredAuthentication required, boolean isGuest) + { + if (authenticator != null) + { + authenticator.authenticate(required, isGuest, req, res); + } + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRuntime#preExecute(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) + */ + @Override + protected boolean preExecute(WebScriptRequest scriptReq, WebScriptResponse scriptRes) + { + return true; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRuntime#postExecute(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) + */ + @Override + protected void postExecute(WebScriptRequest scriptReq, WebScriptResponse scriptRes) + { + } + +} diff --git a/source/java/org/alfresco/web/scripts/WebScriptTransaction.java b/source/java/org/alfresco/web/scripts/WebScriptTransaction.java deleted file mode 100644 index 15fcdb6362..0000000000 --- a/source/java/org/alfresco/web/scripts/WebScriptTransaction.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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; - -import org.alfresco.repo.transaction.TransactionUtil; -import org.alfresco.service.transaction.TransactionService; -import org.alfresco.web.scripts.WebScriptDescription.RequiredTransaction; -import org.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - - -/** - * Web Script Transaction - * - * @author davidc - */ -public class WebScriptTransaction implements MethodInterceptor -{ - // Logger - protected static final Log logger = LogFactory.getLog(WebScriptTransaction.class); - - // dependencies - private TransactionService transactionService; - - - /** - * Sets the transaction service - * - * @param transactionService - */ - public void setTransactionService(TransactionService transactionService) - { - this.transactionService = transactionService; - } - - - /* (non-Javadoc) - * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation) - */ - public Object invoke(final MethodInvocation invocation) - throws Throwable - { - WebScript service = (WebScript)invocation.getThis(); - final WebScriptDescription description = service.getDescription(); - - // encapsulate service call within transaction - TransactionUtil.TransactionWork work = new TransactionUtil.TransactionWork() - { - public Object doWork() throws Throwable - { - if (logger.isDebugEnabled()) - logger.debug("Begin transaction: " + description.getRequiredTransaction()); - - Object retVal = invocation.proceed(); - - if (logger.isDebugEnabled()) - logger.debug("End transaction: " + description.getRequiredTransaction()); - - return retVal; - } - }; - - // execute call within transaction - Object retVal; - if (description.getRequiredTransaction() == RequiredTransaction.required) - { - retVal = TransactionUtil.executeInUserTransaction(transactionService, work); - } - else - { - retVal = TransactionUtil.executeInNonPropagatingUserTransaction(transactionService, work); - } - return retVal; - } - -} diff --git a/source/java/org/alfresco/web/scripts/bean/SearchProxy.java b/source/java/org/alfresco/web/scripts/bean/SearchProxy.java index 5bbf068d5f..e4752196f3 100644 --- a/source/java/org/alfresco/web/scripts/bean/SearchProxy.java +++ b/source/java/org/alfresco/web/scripts/bean/SearchProxy.java @@ -47,6 +47,7 @@ import org.alfresco.web.scripts.FormatRegistry; import org.alfresco.web.scripts.WebScriptException; import org.alfresco.web.scripts.WebScriptRequest; import org.alfresco.web.scripts.WebScriptResponse; +import org.alfresco.web.scripts.WebScriptServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.dom4j.Attribute; @@ -164,7 +165,13 @@ public class SearchProxy extends AbstractWebScript implements InitializingBean logger.debug("Mapping engine '" + engine + "' (mimetype '" + mimetype + "') to url '" + engineUrl + "'"); // issue request against search engine - SearchEngineHttpProxy proxy = new SearchEngineHttpProxy(req.getServicePath() + "/" + req.getContextPath(), engine, engineUrl, res); + // NOTE: This web script must be executed in a HTTP servlet environment + if (!(res instanceof WebScriptServletResponse)) + { + throw new WebScriptException("Search Proxy must be executed in HTTP Servlet environment"); + } + HttpServletResponse servletRes = ((WebScriptServletResponse)req).getHttpServletResponse(); + SearchEngineHttpProxy proxy = new SearchEngineHttpProxy(req.getServicePath() + "/" + req.getContextPath(), engine, engineUrl, servletRes); proxy.service(); } diff --git a/source/java/org/alfresco/web/scripts/portlet/WebClientPortletAuthenticator.java b/source/java/org/alfresco/web/scripts/portlet/WebClientPortletAuthenticator.java new file mode 100644 index 0000000000..0788729c6f --- /dev/null +++ b/source/java/org/alfresco/web/scripts/portlet/WebClientPortletAuthenticator.java @@ -0,0 +1,158 @@ +/* + * 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.portlet; + +import javax.portlet.PortletSession; +import javax.portlet.RenderRequest; +import javax.portlet.RenderResponse; + +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.web.app.servlet.AuthenticationHelper; +import org.alfresco.web.bean.repository.User; +import org.alfresco.web.scripts.WebScriptContext; +import org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +/** + * Portlet authenticator which synchronizes with the Alfresco Web Client authentication + * + * @author davidc + */ +public class WebClientPortletAuthenticator implements WebScriptPortletAuthenticator +{ + // Logger + private static final Log logger = LogFactory.getLog(WebClientPortletAuthenticator.class); + + // dependencies + private AuthenticationService authenticationService; + private WebScriptContext scriptContext; + + + /** + * @param authenticationService + */ + public void setAuthenticationService(AuthenticationService authenticationService) + { + this.authenticationService = authenticationService; + } + + /** + * @param scriptContext + */ + public void setScriptContext(WebScriptContext scriptContext) + { + this.scriptContext = scriptContext; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.portlet.WebScriptPortletAuthenticator#authenticate(org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication, boolean, javax.portlet.RenderRequest, javax.portlet.RenderResponse) + */ + public void authenticate(RequiredAuthentication required, boolean isGuest, RenderRequest req, RenderResponse res) + { + PortletSession session = req.getPortletSession(); + String portalUser = req.getRemoteUser(); + + if (logger.isDebugEnabled()) + { + logger.debug("JSR-168 Remote user: " + portalUser); + } + + if (isGuest || portalUser == null) + { + if (logger.isDebugEnabled()) + logger.debug("Authenticating as Guest"); + + // authenticate as guest + AuthenticationUtil.setCurrentUser(AuthenticationUtil.getGuestUserName()); + + if (logger.isDebugEnabled()) + logger.debug("Setting Web Client authentication context for guest"); + + createWebClientUser(session); + removeSessionInvalidated(session); + } + else + { + if (logger.isDebugEnabled()) + logger.debug("Authenticating as user " + portalUser); + + AuthenticationUtil.setCurrentUser(portalUser); + + // determine if Web Client context needs to be updated + User user = getWebClientUser(session); + if (user == null || !portalUser.equals(user.getUserName())) + { + if (logger.isDebugEnabled()) + logger.debug("Setting Web Client authentication context for user " + portalUser); + + createWebClientUser(session); + removeSessionInvalidated(session); + } + } + } + + /** + * Helper. Remove Web Client session invalidated flag + * + * @param session + */ + private void removeSessionInvalidated(PortletSession session) + { + session.removeAttribute(AuthenticationHelper.SESSION_INVALIDATED, PortletSession.APPLICATION_SCOPE); + } + + /** + * Helper. Create Web Client session user + * + * @param session + */ + private void createWebClientUser(PortletSession session) + { + NodeRef personRef = scriptContext.getPerson(); + User user = new User(authenticationService.getCurrentUserName(), authenticationService.getCurrentTicket(), personRef); + NodeRef homeRef = scriptContext.getUserHome(personRef); + if (homeRef != null) + { + user.setHomeSpaceId(homeRef.getId()); + } + session.setAttribute(AuthenticationHelper.AUTHENTICATION_USER, user, PortletSession.APPLICATION_SCOPE); + } + + /** + * Helper. Get Web Client session user + * + * @param session + * @return + */ + private User getWebClientUser(PortletSession session) + { + return (User)session.getAttribute(AuthenticationHelper.AUTHENTICATION_USER, PortletSession.APPLICATION_SCOPE); + } + +} diff --git a/source/java/org/alfresco/web/scripts/portlet/WebScriptPortlet.java b/source/java/org/alfresco/web/scripts/portlet/WebScriptPortlet.java new file mode 100644 index 0000000000..6184cddf5c --- /dev/null +++ b/source/java/org/alfresco/web/scripts/portlet/WebScriptPortlet.java @@ -0,0 +1,287 @@ +/* + * 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.portlet; + +import java.io.IOException; +import java.util.Map; + +import javax.portlet.ActionRequest; +import javax.portlet.ActionResponse; +import javax.portlet.Portlet; +import javax.portlet.PortletConfig; +import javax.portlet.PortletContext; +import javax.portlet.PortletException; +import javax.portlet.PortletMode; +import javax.portlet.PortletSecurityException; +import javax.portlet.RenderRequest; +import javax.portlet.RenderResponse; +import javax.portlet.WindowState; + +import org.alfresco.service.transaction.TransactionService; +import org.alfresco.web.scripts.DeclarativeWebScriptRegistry; +import org.alfresco.web.scripts.WebScript; +import org.alfresco.web.scripts.WebScriptDescription; +import org.alfresco.web.scripts.WebScriptMatch; +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptResponse; +import org.alfresco.web.scripts.WebScriptRuntime; +import org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.web.context.WebApplicationContext; + + +/** + * Generic JSR-168 Portlet for hosting an Alfresco Web Script as a Portlet. + * + * Accepts the following init-config: + * + * scriptUrl => the url of the web script to host e.g. /alfresco/service/mytasks + * + * @author davidc + */ +public class WebScriptPortlet implements Portlet +{ + private static Log logger = LogFactory.getLog(WebScriptPortlet.class); + + // Portlet initialisation + protected String initScriptUrl = null; + + // Component Dependencies + protected DeclarativeWebScriptRegistry registry; + protected TransactionService transactionService; + protected WebScriptPortletAuthenticator authenticator; + + + /* (non-Javadoc) + * @see javax.portlet.Portlet#init(javax.portlet.PortletConfig) + */ + public void init(PortletConfig config) throws PortletException + { + initScriptUrl = config.getInitParameter("scriptUrl"); + PortletContext portletCtx = config.getPortletContext(); + WebApplicationContext ctx = (WebApplicationContext)portletCtx.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); + registry = (DeclarativeWebScriptRegistry)ctx.getBean("webscripts.registry"); + transactionService = (TransactionService)ctx.getBean("transactionComponent"); + authenticator = (WebScriptPortletAuthenticator)ctx.getBean("webscripts.authenticator.jsr168"); + } + + /* (non-Javadoc) + * @see javax.portlet.Portlet#processAction(javax.portlet.ActionRequest, javax.portlet.ActionResponse) + */ + public void processAction(ActionRequest req, ActionResponse res) throws PortletException, PortletSecurityException, IOException + { + Map params = req.getParameterMap(); + for (Map.Entry param : params.entrySet()) + { + String name = param.getKey(); + if (name.equals("scriptUrl") || name.startsWith("arg.")) + { + res.setRenderParameter(name, param.getValue()); + } + } + } + + /* (non-Javadoc) + * @see javax.portlet.Portlet#render(javax.portlet.RenderRequest, javax.portlet.RenderResponse) + */ + public void render(RenderRequest req, RenderResponse res) throws PortletException, PortletSecurityException, IOException + { + PortletMode portletMode = req.getPortletMode(); + if (PortletMode.VIEW.equals(portletMode)) + { + doView(req, res); + } +// else if (PortletMode.HELP.equals(portletMode)) +// { +// doHelp(request, response); +// } +// else if (PortletMode.EDIT.equals(portletMode)) +// { +// doEdit(request, response); +// } + } + + /* (non-Javadoc) + * @see javax.portlet.Portlet#destroy() + */ + public void destroy() + { + } + + /** + * Render Web Script view + * + * @param req + * @param res + * @throws PortletException + * @throws PortletSecurityException + * @throws IOException + */ + protected void doView(RenderRequest req, RenderResponse res) throws PortletException, PortletSecurityException, IOException + { + // + // Establish Web Script URL + // + + String scriptUrl = req.getParameter("scriptUrl"); + if (scriptUrl != null) + { + // build web script url from render request + String scriptUrlArgs = ""; + Map params = req.getParameterMap(); + for (Map.Entry param : params.entrySet()) + { + String name = param.getKey(); + if (name.startsWith("arg.")) + { + String argName = name.substring("arg.".length()); + for (String argValue : param.getValue()) + { + scriptUrlArgs += (scriptUrlArgs.length() == 0) ? "" : "&"; + scriptUrlArgs += argName + "=" + argValue; + } + } + } + scriptUrl += "?" + scriptUrlArgs; + } + else + { + // retrieve initial scriptUrl as configured by Portlet + scriptUrl = initScriptUrl; + if (scriptUrl == null) + { + throw new PortletException("Initial Web script URL has not been specified."); + } + } + + // + // Execute Web Script + // + + if (logger.isDebugEnabled()) + logger.debug("Processing portal render request " + req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort() + "/" + req.getContextPath() + " (scriptUrl=" + scriptUrl + ")"); + + WebScriptRuntime runtime = new WebScriptPortalRuntime(req, res, scriptUrl); + runtime.executeScript(); + } + + /** + * JSR-168 Web Script Runtime + * + * @author davidc + */ + private class WebScriptPortalRuntime extends WebScriptRuntime + { + private RenderRequest req; + private RenderResponse res; + private String[] requestUrlParts; + + + /** + * Construct + * @param req + * @param res + * @param requestUrl + */ + public WebScriptPortalRuntime(RenderRequest req, RenderResponse res, String requestUrl) + { + super(registry, transactionService); + this.req = req; + this.res = res; + this.requestUrlParts = WebScriptPortletRequest.getScriptUrlParts(requestUrl); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRuntime#getScriptMethod() + */ + @Override + protected String getScriptMethod() + { + return "get"; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRuntime#getScriptUrl() + */ + @Override + protected String getScriptUrl() + { + return requestUrlParts[2]; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRuntime#createRequest(org.alfresco.web.scripts.WebScriptMatch) + */ + @Override + protected WebScriptRequest createRequest(WebScriptMatch match) + { + return new WebScriptPortletRequest(req, requestUrlParts, match); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRuntime#createResponse() + */ + @Override + protected WebScriptResponse createResponse() + { + return new WebScriptPortletResponse(res); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRuntime#authenticate(org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication, boolean) + */ + @Override + protected void authenticate(RequiredAuthentication required, boolean isGuest) + { + authenticator.authenticate(required, isGuest, req, res); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRuntime#preExecute(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) + */ + @Override + protected boolean preExecute(WebScriptRequest scriptReq, WebScriptResponse scriptRes) + { + // Set Portlet title based on Web Script + WebScript script = scriptReq.getServiceMatch().getWebScript(); + WebScriptDescription desc = script.getDescription(); + res.setTitle(desc.getShortName()); + + // Note: Do not render script if portlet window is minimized + return !WindowState.MINIMIZED.equals(req.getWindowState()); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRuntime#postExecute(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) + */ + @Override + protected void postExecute(WebScriptRequest scriptReq, WebScriptResponse scriptRes) + { + } + + } + +} diff --git a/source/java/org/alfresco/web/scripts/portlet/WebScriptPortletAuthenticator.java b/source/java/org/alfresco/web/scripts/portlet/WebScriptPortletAuthenticator.java new file mode 100644 index 0000000000..4cdcb8c311 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/portlet/WebScriptPortletAuthenticator.java @@ -0,0 +1,51 @@ +/* + * 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.portlet; + +import javax.portlet.RenderRequest; +import javax.portlet.RenderResponse; + +import org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication; + + +/** + * Web Script Authenticator for the JSR-168 environment + * + * @author davidc + */ +public interface WebScriptPortletAuthenticator +{ + + /** + * Authenticate Web Script execution + * + * @param required required level of authentication + * @param isGuest is Guest accessing the web script + * @param req portlet render request + * @param res portlet render response + */ + public void authenticate(RequiredAuthentication required, boolean isGuest, RenderRequest req, RenderResponse res); + +} diff --git a/source/java/org/alfresco/web/scripts/portlet/WebScriptPortletRequest.java b/source/java/org/alfresco/web/scripts/portlet/WebScriptPortletRequest.java new file mode 100644 index 0000000000..90e651563f --- /dev/null +++ b/source/java/org/alfresco/web/scripts/portlet/WebScriptPortletRequest.java @@ -0,0 +1,265 @@ +/* + * 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.portlet; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import javax.portlet.PortletRequest; + +import org.alfresco.web.scripts.WebScriptMatch; +import org.alfresco.web.scripts.WebScriptRequest; + + +/** + * JSR-168 Web Script Request + * + * @author davidc + */ +public class WebScriptPortletRequest implements WebScriptRequest +{ + /** Portlet Request */ + private PortletRequest req; + + /** Script Url components */ + private String contextPath; + private String servletPath; + private String pathInfo; + private String queryString; + private Map queryArgs; + + /** Service bound to this request */ + private WebScriptMatch serviceMatch; + + + /** + * Splits a portlet scriptUrl into its component parts + * + * @param scriptUrl url e.g. /alfresco/service/mytasks?f=1 + * @return url parts [0] = context (e.g. alfresco), [1] = servlet (e.g. service), [2] = script (e.g. mytasks), [3] = args (e.g. f=1) + */ + public static String[] getScriptUrlParts(String scriptUrl) + { + String[] urlParts = new String[4]; + String path; + String queryString; + + int argsIndex = scriptUrl.indexOf("?"); + if (argsIndex != -1) + { + path = scriptUrl.substring(0, argsIndex); + queryString = scriptUrl.substring(argsIndex + 1); + } + else + { + path = scriptUrl; + queryString = null; + } + + String[] pathSegments = path.split("/"); + String pathInfo = ""; + for (int i = 3; i < pathSegments.length; i++) + { + pathInfo += "/" + pathSegments[i]; + } + + urlParts[0] = "/" + pathSegments[1]; // context path + urlParts[1] = "/" + pathSegments[2]; // servlet path + urlParts[2] = pathInfo; // path info + urlParts[3] = queryString; // query string + + return urlParts; + } + + + /** + * Construct + * + * @param req + * @param scriptUrl + * @param serviceMatch + */ + WebScriptPortletRequest(PortletRequest req, String scriptUrl, WebScriptMatch serviceMatch) + { + this(req, getScriptUrlParts(scriptUrl), serviceMatch); + } + + /** + * Construct + * + * @param req + * 'param scriptUrlParts + * @param serviceMatch + */ + WebScriptPortletRequest(PortletRequest req, String[] scriptUrlParts, WebScriptMatch serviceMatch) + { + this.req = req; + this.contextPath = scriptUrlParts[0]; + this.servletPath = scriptUrlParts[1]; + this.pathInfo = scriptUrlParts[2]; + this.queryString = scriptUrlParts[3]; + this.queryArgs = new HashMap(); + if (this.queryString != null) + { + String[] args = this.queryString.split("&"); + for (String arg : args) + { + String[] parts = arg.split("="); + // TODO: Handle multi-value parameters + this.queryArgs.put(parts[0], parts.length == 2 ? parts[1] : ""); + } + } + this.serviceMatch = serviceMatch; + } + + /** + * Gets the Portlet Request + * + * @return Portlet Request + */ + public PortletRequest getPortletRequest() + { + return req; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getServiceMatch() + */ + public WebScriptMatch getServiceMatch() + { + return serviceMatch; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getServerPath() + */ + public String getServerPath() + { + return req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort(); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getContextPath() + */ + public String getContextPath() + { + return contextPath; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getServiceContextPath() + */ + public String getServiceContextPath() + { + return getContextPath() + servletPath; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getServicePath() + */ + public String getServicePath() + { + return getServiceContextPath() + pathInfo; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getURL() + */ + public String getURL() + { + return getServicePath() + (queryString != null ? "?" + queryString : ""); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getQueryString() + */ + public String getQueryString() + { + return queryString; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getParameterNames() + */ + public String[] getParameterNames() + { + Set keys = queryArgs.keySet(); + String[] names = new String[keys.size()]; + keys.toArray(names); + return names; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getParameter(java.lang.String) + */ + public String getParameter(String name) + { + return queryArgs.get(name); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getExtensionPath() + */ + public String getExtensionPath() + { + String servicePath = serviceMatch.getPath(); + String extensionPath = pathInfo; + int extIdx = extensionPath.indexOf(servicePath); + if (extIdx != -1) + { + int extLength = (servicePath.endsWith("/") ? servicePath.length() : servicePath.length() + 1); + extensionPath = extensionPath.substring(extIdx + extLength); + } + return extensionPath; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#isGuest() + */ + public boolean isGuest() + { + return Boolean.valueOf(queryArgs.get("guest")); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getFormat() + */ + public String getFormat() + { + String format = queryArgs.get("format"); + return (format == null || format.length() == 0) ? "" : format; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getAgent() + */ + public String getAgent() + { + // NOTE: rely on default agent mappings + return null; + } + +} diff --git a/source/java/org/alfresco/web/scripts/portlet/WebScriptPortletResponse.java b/source/java/org/alfresco/web/scripts/portlet/WebScriptPortletResponse.java new file mode 100644 index 0000000000..90e6f66909 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/portlet/WebScriptPortletResponse.java @@ -0,0 +1,109 @@ +/* + * 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.portlet; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.Writer; + +import javax.portlet.PortletURL; +import javax.portlet.RenderResponse; + +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptResponse; + + +/** + * JSR-168 Web Script Response + * + * @author davidc + */ +public class WebScriptPortletResponse implements WebScriptResponse +{ + /** Portlet response */ + private RenderResponse res; + + + /** + * Construct + * + * @param res + */ + WebScriptPortletResponse(RenderResponse res) + { + this.res = res; + } + + /** + * Gets the Portlet Render Response + * + * @return render response + */ + public RenderResponse getRenderResponse() + { + return res; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptResponse#setContentType(java.lang.String) + */ + public void setContentType(String contentType) + { + res.setContentType(contentType); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptResponse#getWriter() + */ + public Writer getWriter() throws IOException + { + return res.getWriter(); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptResponse#getOutputStream() + */ + public OutputStream getOutputStream() throws IOException + { + return res.getPortletOutputStream(); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptResponse#encodeScriptUrl(java.lang.String) + */ + public String encodeScriptUrl(String url) + { + WebScriptRequest req = new WebScriptPortletRequest(null, url, null); + PortletURL portletUrl = res.createActionURL(); + portletUrl.setParameter("scriptUrl", req.getServicePath()); + String[] parameterNames = req.getParameterNames(); + for (String parameterName : parameterNames) + { + portletUrl.setParameter("arg." + parameterName, req.getParameter(parameterName)); + } + return portletUrl.toString(); + } + +} diff --git a/source/web/WEB-INF/portlet.xml b/source/web/WEB-INF/portlet.xml index e7f70dae3e..9fe017a469 100644 --- a/source/web/WEB-INF/portlet.xml +++ b/source/web/WEB-INF/portlet.xml @@ -21,4 +21,68 @@ alfresco-client-portlet + + + My Tasks + AlfrescoMyTasks + org.alfresco.web.scripts.portlet.WebScriptPortlet + + + scriptUrl + /alfresco/service/mytasks + + + + text/html + VIEW + + + + My Tasks + My Tasks + + + + + Document List + AlfrescoDocList + org.alfresco.web.scripts.portlet.WebScriptPortlet + + + scriptUrl + /alfresco/service/doclist?p=/Company Home/Guest Home + + + + text/html + VIEW + + + + Document List + Document List + + + + + My Web Forms + AlfrescoMyWebForms + org.alfresco.web.scripts.portlet.WebScriptPortlet + + + scriptUrl + /alfresco/service/mywebforms + + + + text/html + VIEW + + + + My Web Forms + My Web Forms + + + diff --git a/source/web/WEB-INF/web.xml b/source/web/WEB-INF/web.xml index 4388ef3fd2..e669bda383 100644 --- a/source/web/WEB-INF/web.xml +++ b/source/web/WEB-INF/web.xml @@ -250,6 +250,10 @@ apiServlet org.alfresco.web.scripts.WebScriptServlet + + authenticator + webscripts.authenticator.webclient +